﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using Noris.Tools.TraceVisualiser.Support;
using Djs.Tools.XmlPersistor;
using Noris.Tools.TraceVisualiser.Components;
using Noris.Tools.TraceVisualiser.TraceData;

namespace Noris.Tools.TraceVisualiser.Components
{
    #region class ColorList : Seznam barevných položek = více řádků třídy ColorItem. Datová vrstva.
    /// <summary>
    /// ColorList : Seznam barevných položek = více řádků třídy ColorItem. Datová vrstva.
    /// </summary>
    public class ColorList
    {
		#region Konstrukce
	    public ColorList()
        {
            this.Init();
        }
        public ColorList(string configFile)
        {
            this.Init();
            this.ConfigFile = configFile;
        }
        protected void Init()
        {
			this.ColorItems = new Dictionary<string, ColorItem>();
            this.EmptyColumnCount = 1;
            this.PrepareStyles();
            this.BackColorRow = Color.MintCream;
			this.DefaultItemColor = Color.PaleTurquoise;
            this.DefaultItemName = "Default";
			this.VariationEnabled = true;
			this.VariationInterval = 16;
			this.VariationCount = 9;
        }
		private void PrepareStyles()
		{
			this.NameCellStyle = new DataGridViewCellStyle();
			this.NameCellStyle.BackColor = this.BackColorRow;
			this.NameCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
			this.NameCellStyle.WrapMode = DataGridViewTriState.NotSet;
		}
		#endregion
		#region Property
        /// <summary>
        /// Soubor do něhož se ukládá běžná konfigurace.
        /// </summary>
        [PersistingEnabled(false)]
        public string ConfigFile { get; set; }
        /// <summary>
        /// Příznak true, když je zadán výchozí konfigurační soubor (this.ConfigFile není prázdný)
        /// </summary>
        public bool ConfigFileValid { get { return !String.IsNullOrEmpty(this.ConfigFile); } }
        /// <summary>
        /// Příznak true, když je zadán výchozí konfigurační soubor a když existuje
        /// </summary>
        public bool ConfigFileExists { get { return this.ConfigFileValid && System.IO.File.Exists(this.ConfigFile); } }
		/// <summary>
        /// Seznam barevných položek. Seznam nelze editovat.
        /// </summary>
		public List<ColorItem> List { get { return new List<ColorItem>(this.ColorItems.Values); } }
		/// <summary>
		/// Seznam barevných položek. Seznam nelze editovat.
		/// Seznam je setříděný podle Name.
		/// </summary>
		public List<ColorItem> ListSortedByName
		{
			get
			{
				List<ColorItem> list = new List<ColorItem>(this.ColorItems.Values);
				list.Sort(ColorItem.CompareByName);
				return list;
			}
		}
		/// <summary>
		/// Index barevných položek. Zde je základní úložiště dat.
		/// </summary>
        [PersistingEnabled(false)]
		private Dictionary<string, ColorItem> ColorItems { get; set; }
		/// <summary>
		/// Barva pozadí ve sloupcích Text a Nová barva
		/// </summary>
		[DefaultValue("Color.MintCream")]
		public Color BackColorRow
		{
			get { return this.NameCellStyle.BackColor; }
			set { this.NameCellStyle.BackColor = value; }
		}
		/// <summary>
		/// Defaultní barva prvku, pokud bude prvek bez barev.
		/// </summary>
		public Color DefaultItemColor { get; set; }
        /// <summary>
        /// Název defaultního prvku - zobrazuje se uživateli, ten může barvu změnit. Nelze změnit její název.
        /// </summary>
        public string DefaultItemName { get; private set; }
		/// <summary>
		/// Styl buněk pro sloupec Name
		/// </summary>
        [PersistingEnabled(false)]
        internal DataGridViewCellStyle NameCellStyle { get; private set; }
		/// <summary>
		/// Počet prázdných sloupců za poslední barvou.
		/// Platné hodnoty 1 ÷ 8, zadání jiné hodnoty vede k zadání odpovídající krajní hodnoty.
		/// </summary>
		public int EmptyColumnCount
		{
			get { return _EmptyColumnCount; }
			set
			{
				if (value < 1) _EmptyColumnCount = 1;
				else if (value > 8) _EmptyColumnCount = 8;
				else _EmptyColumnCount = value;
			}
		}
		private int _EmptyColumnCount;
		/// <summary>
		/// Povolení barevných variant
		/// </summary>
		public bool VariationEnabled { get; set; }
		/// <summary>
		/// Rozsah barevných variant
		/// </summary>
		public int VariationInterval
		{
			get { return this._VariationInterval; }
			set { this._VariationInterval = (value < 0 ? 0 : (value > 48 ? 48 : value)); }
		}
		private int _VariationInterval;
		/// <summary>
		/// Počet barevných variant: povolené hodnoty jsou: 1, 3, 6, 9. Jiné hodnoty budou ignorovány.
		/// </summary>
		public int VariationCount
		{
			get { return this._VariationCount; }
			set
			{
				if (value == 1 || value == 3 || value == 6 || value == 9)
					this._VariationCount = value;
			}
		}
		private int _VariationCount;
		#endregion
		#region Správa dat (Add, TryGet, Remove)
		/// <summary>
		/// Vkládá novou položku - bez barev.
		/// Pokud položka daného jména již existuje, vyhodí chybu.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="name"></param>
        public void Add(string key, string name)
        {
			this._Add(key, name, null, AppendMode.Error, AppendMode.Replace);
        }
		/// <summary>
		/// Vkládá novou položku - včetně barev.
		/// Pokud položka daného jména již existuje, vyhodí chybu.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="colors"></param>
		public void Add(string key, params Color[] colors)
		{
			this._Add(key, ColorItem.GetName(key), colors, AppendMode.Error, AppendMode.Replace);
		}
		/// <summary>
		/// Vkládá novou položku - včetně barev.
		/// Pokud položka daného jména již existuje, vyhodí chybu.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="name"></param>
		/// <param name="colors"></param>
        public void Add(string key, string name, params Color[] colors)
        {
			this._Add(key, name, colors, AppendMode.Error, AppendMode.Replace);
        }
		/// <summary>
		/// Vkládá novou položku - bez barev.
		/// Pokud položka daného jména již existuje, sloučí jejich barvy.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="name"></param>
		public void Append(string key, string name)
		{
			this._Add(key, name, null, AppendMode.Merge, AppendMode.Merge);
		}
		/// <summary>
		/// Vkládá novou položku - včetně barev.
		/// Pokud položka daného jména již existuje, sloučí jejich barvy.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="colors"></param>
		public void Append(string key, params Color[] colors)
		{
			this._Add(key, ColorItem.GetName(key), colors, AppendMode.Merge, AppendMode.Merge);
		}
		/// <summary>
		/// Vkládá novou položku - včetně barev.
		/// Pokud položka daného jména již existuje, sloučí jejich barvy.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="name"></param>
		/// <param name="colors"></param>
		public void Append(string key, string name, params Color[] colors)
		{
			this._Add(key, name, colors, AppendMode.Merge, AppendMode.Merge);
		}
        /// <summary>
        /// Vkládá novou položku - bez barev.
        /// Pokud položka daného jména již existuje, sloučí jejich barvy.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="name"></param>
        public void Append(string key, string name, AppendMode itemMode, AppendMode colorMode)
        {
            this._Add(key, name, null, itemMode, colorMode);
        }
        /// <summary>
        /// Vkládá novou položku - včetně barev.
        /// Pokud položka daného jména již existuje, sloučí jejich barvy.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="colors"></param>
        public void Append(string key, AppendMode itemMode, AppendMode colorMode, params Color[] colors)
        {
            this._Add(key, ColorItem.GetName(key), colors, itemMode, colorMode);
        }
        /// <summary>
        /// Vkládá novou položku - včetně barev.
        /// Pokud položka daného jména již existuje, sloučí jejich barvy.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="name"></param>
        /// <param name="colors"></param>
        public void Append(string key, string name, AppendMode itemMode, AppendMode colorMode, params Color[] colors)
        {
            this._Add(key, name, colors, itemMode, colorMode);
        }
        /// <summary>
		/// Vrátí informaci o tom, že prvek s daným klíčem existuje.
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public bool ContainKey(string key)
		{
			string keyLow = ColorItem.GetKey(key);
			return this.ColorItems.ContainsKey(keyLow);
		}
		/// <summary>
		/// Vrátí prvek pro daný klíč
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public ColorItem Get(string key)
		{
			string keyLow = ColorItem.GetKey(key);
			if (!this.ColorItems.ContainsKey(keyLow))
				throw new ArgumentException("ColorList does not contain item with key " + key);
			return this.ColorItems[keyLow];
		}
		/// <summary>
		/// Zkusí najít prvek pro daný klíč.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="item"></param>
		/// <returns></returns>
		public bool TryGetValue(string key, out ColorItem item)
		{
			string keyLow = ColorItem.GetKey(key);
			return this.ColorItems.TryGetValue(keyLow, out item);
		}
		/// <summary>
		/// Odebere prvek pro daný klíč
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public void Remove(string key)
		{
			string keyLow = ColorItem.GetKey(key);
			if (!this.ColorItems.ContainsKey(keyLow))
				throw new ArgumentException("ColorList does not contain item with key " + key);
			this.ColorItems.Remove(keyLow);
		}
		/// <summary>
		/// Smaže všechny prvky
		/// </summary>
		public void Clear()
		{
            if (this.ColorItems == null)
                this.ColorItems = new Dictionary<string, ColorItem>();
            else if (this.ColorItems.Count > 0)
    			this.ColorItems.Clear();
		}
		/// <summary>
		/// Přidá nová data
		/// </summary>
		/// <param name="key">Klíč vkládané položky</param>
		/// <param name="name">Uživatelský název nové položky</param>
		/// <param name="colors">Sada barev</param>
		/// <param name="itemMode">Režim slučování položek</param>
        /// <param name="colorMode">Režim slučování jednotlivých barev v položce</param>
		private void _Add(string key, string name, IEnumerable<Color> colors, AppendMode itemMode, AppendMode colorMode)
		{
			string keyLow = ColorItem.GetKey(key);
            ColorItem colorItem = new ColorItem(this, key, name, colors);
            this._Append(keyLow, colorItem, itemMode, colorMode);
		}
        /// <summary>
        /// Přidá nová data
        /// </summary>
        /// <param name="keyLow">Klíč položky</param>
        /// <param name="colorItem">Data položky (ukládá se klon)</param>
        /// <param name="itemMode">Režim slučování položek</param>
        /// <param name="colorMode">Režim slučování jednotlivých barev v položce</param>
        private void _Append(string keyLow, ColorItem colorItem, AppendMode itemMode, AppendMode colorMode)
        {
            ColorItem item;
            bool itemExist = this.ColorItems.TryGetValue(keyLow, out item);
            if (!itemExist)
            {	// Pokud u nás položka neexistuje, přidám si ji:
                this.ColorItems.Add(keyLow, colorItem.GetClone(this));
            }
            else
            {
                switch (itemMode)
                {
                    case AppendMode.Replace:
                        this.ColorItems[keyLow] = colorItem.GetClone(this);
                        break;
                    case AppendMode.Merge:
                        {
                            switch (colorMode)
                            {
                                case AppendMode.Replace:
                                    item.SetColors(colorItem.Colors);
                                    break;
                                case AppendMode.Merge:
                                    item.Merge(colorItem.Colors);
                                    break;
                                case AppendMode.Leave:
                                    break;
                                case AppendMode.Error:
                                    break;
                            }
                        }
                        break;
                    case AppendMode.Leave:
                        break;
                    case AppendMode.Error:
                        throw new ArgumentException("ColorList already contain item with key = \"" + keyLow + "\"");
                }
            }
        }
		#endregion
		#region Nalezení barevné položky pro daný klíč, hledání "nahoru" - po tečkách, tvorba barevné varianty
		/// <summary>
		/// Vrátí barvu objektu dané skupiny a daného čísla.
		/// Skupina = například "server", "cowley", "instance".
		/// V jedné skupině může být víc než jedna barva, pak se konkrétní barva určí podle čísla objektu.
		/// </summary>
		/// <param name="key">Klíč hledaného prvku</param>
		/// <param name="defaultKey">Defaultní klíč</param>
		/// <param name="insertAbsentKeys">Pokud je zadán klíč, který neexistuje, má se přidat do paměti?</param>
		/// <param name="objectId"></param>
		/// <returns></returns>
		internal Color GetColor(string key, int objectId, bool insertAbsentKeys)
		{
			bool isKey = !String.IsNullOrEmpty(key);
			bool isDef = !String.IsNullOrEmpty(this.DefaultItemName);
			if (!isKey && !isDef)                         // Pokud není zadán ani key a ani Default, vracím DefaultItemColor.
				return this.DefaultItemColor;
            string keyFind = (isKey ? key : this.DefaultItemName);  // Klíč: prioritně zadaný Key, ale pokud není zadán tak Default
			List<string> keys = SplitKey(keyFind, SplitArrayDirect.FromDetail);  // Vytvořit řadu klíčů od nejdelšího po nejkratší. bez úpravy ToLower().
			if (isKey && isDef)
                keys.Add(this.DefaultItemName);           // Pokud jsou zadány Key i Default, pak se Default přidá jako poslední hodnota do seznamu
			ColorItem item = null;
			foreach (string keyOne in keys)
			{	// Postupně pro klíčové texty (od nejdelšího k nejkratšímu, a na posledním místě Default):
				string keyLow = ColorItem.GetKey(keyOne);
				bool exists = this.ColorItems.TryGetValue(keyLow, out item);
				if (!exists)
				{	// Tento klíč neexistuje => pokud je možno, přidáme jej:
					if (insertAbsentKeys)
						this.Add(keyLow, keyOne);          // keyLow je Lower, keyOne je bez úpravy ToLower.
				}
				else if (item != null && item.ContainColors)
					// Korektní data beru jako OK a končím s hledáním:
					break;
			}
			if (item == null && (item != null && !item.ContainColors))           // Položka nenalezena, nebo nalezena ale bez barev => vrátím default barvu
				return this.DefaultItemColor;

			return item.GetColor(objectId);
		}
		/// <summary>
		/// Zadaný text rozdělí na prvky, které postupně obsahují části klíče oddělené tečkami.
		/// Ale nikoli jako jednoduchý Split, ale jako "Schody" : "1.2.3.4" : "1", "1.2", "1.2.3", "1.2.3.4".
		/// Metoda neupravuje text ToLower(), ale dává na jednotlivé prvky Trim().
		/// </summary>
		/// <param name="key">Text, který chci rozdělit. Metoda jej neupravuje ToLower(), ale dává Trim().</param>
		/// <param name="direct">Směr prvků ve vráceném poli: od nejkratšího nebo od nejdelšího</param>
		/// <returns></returns>
		internal static List<string> SplitKey(string key, SplitArrayDirect direct)
		{
			List<string> result = new List<string>();
			if (!String.IsNullOrEmpty(key))
			{
				// string keyLow = ColorItem.GetKey(key);             // Trim, ToLower
				// Rozdělit text "NrsCowley.LCS.Admin.Class.Method()" na prvky: { "NrsCowley", "LCS", "Admin", "Class", "Method()" }:
				string[] items = key.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
				string text = "";
				foreach (string item in items)
				{
					if (!String.IsNullOrEmpty(item))
					{
						text += (text.Length == 0 ? "" : ".") + item.Trim();  // Postupně zde vzniká text: "NrsCowley"; "NrsCowley.LCS", "NrsCowley.LCS.Admin", ...
						result.Add(text);                                     // A v tomto pořadí se vkládá do výsledku.
					}
				}
			}
			// Pole result je vytvořeno ve směru Global (tj. od nejkratšího textu k nejdelšímu).
			// Pokud je požadován směr opačný, obrátím směr nyní:
			if (direct == SplitArrayDirect.FromDetail)
				result.Reverse();

			return result;
		}
		/// <summary>
		/// Vrátí barevnou variantu pro danou barvu a číslo.
		/// Pro číslo 0 vrací vstupní barvu.
		/// Generuje dalších 8 barev, 
		/// </summary>
		/// <param name="color"></param>
		/// <param name="variation"></param>
		/// <returns></returns>
		public static System.Drawing.Color GetColorVariation(System.Drawing.Color color, int variation, int interval)
		{
			return GetColorVariation(color, variation, interval, 9);
		}
		/// <summary>
		/// Vrátí barevnou variantu pro danou barvu a číslo.
		/// Pro číslo 0 vrací vstupní barvu.
		/// Generuje dalších 8 barev, 
		/// </summary>
		/// <param name="color"></param>
		/// <param name="variation"></param>
		/// <returns></returns>
		public static System.Drawing.Color GetColorVariation(System.Drawing.Color color, int variation, int interval, int count)
		{
			if (variation == 0) return color;

			// Vytvoříme variantu barvy, v celkovém počtu 9 kousků (kvůli hezké editaci, viz panel Noris.Tools.TraceVisualiser.Forms.ColorSamplePanel)
			int intervl = (interval < 0 ? 0 : (interval > 48 ? 48 : interval));
			int variate = variation % (count < 1 ? 1 : (count > 9 ? 9 : count));
			int r = color.R;
			int g = color.G;
			int b = color.B;
			switch (variate)
			{
				case 0:
					break;
				case 1:
					r += intervl;
					break;
				case 2:
					r -= intervl;
					break;
				case 3:
					g += intervl;
					break;
				case 4:
					g -= intervl;
					break;
				case 5:
					b += intervl;
					break;
				case 6:
					b -= intervl;
					break;
				case 7:
					b += intervl;
					r -= intervl;
					break;
				case 8:
					b -= intervl;
					g += intervl;
					break;
			}
			r = (r < 0 ? 0 : (r > 255 ? 255 : r));
			g = (g < 0 ? 0 : (g > 255 ? 255 : g));
			b = (b < 0 ? 0 : (b > 255 ? 255 : b));
			return Color.FromArgb(color.A, r, g, b);
		}
		/// <summary>
		/// Určuje směr rozkladu textu do pole v metodě SplitKey(): od detailu (nejdelší string) nebo od globálního klíče (nejkratší string)
		/// </summary>
		internal enum SplitArrayDirect { None, FromDetail, FromGlobal }
		#endregion
		#region Příprava Gridu
		/// <summary>
		/// Naplní do daného objektu DataGridView svoje prvky
		/// </summary>
		/// <param name="dataGridView">Grid, do něhož se prvky vkládají</param>
		public void FillGridView(DataGridView dataGridView)
		{
			this.FillGridView(dataGridView, -1, false);
		}
		/// <summary>
		/// Naplní do daného objektu DataGridView svoje prvky
		/// </summary>
		/// <param name="dataGridView">Grid, do něhož se prvky vkládají</param>
		/// <param name="nameColumnWidth">Šířka sloupce se jmény</param>
		public void FillGridView(DataGridView dataGridView, int nameColumnWidth)
		{
			this.FillGridView(dataGridView, nameColumnWidth, false);
		}
		/// <summary>
		/// Naplní do daného objektu DataGridView svoje prvky
		/// </summary>
		/// <param name="dataGridView">Grid, do něhož se prvky vkládají</param>
		/// <param name="autoNameColumnWidth">Přizpůsobit šířku sloupce se jmény šířce gridu</param>
		public void FillGridView(DataGridView dataGridView, bool autoNameColumnWidth)
		{
			this.FillGridView(dataGridView, -1, autoNameColumnWidth);
		}
		/// <summary>
		/// Naplní do daného objektu DataGridView svoje prvky
		/// </summary>
		/// <param name="dataGridView">Grid, do něhož se prvky vkládají</param>
		/// <param name="nameColumnWidth">Šířka sloupce se jmény</param>
		/// <param name="autoNameColumnWidth">Přizpůsobit šířku sloupce se jmény šířce gridu</param>
		protected void FillGridView(DataGridView dataGridView, int nameColumnWidth, bool autoNameColumnWidth)
        {
			this.SetProperty(dataGridView);

            dataGridView.Columns.Clear();
            dataGridView.Rows.Clear();

			List<ColorItem> list = this.ListSortedByName;
            foreach (ColorItem colorItem in list)
            {
                DataGridViewRow row = colorItem.GetDataGridRow(dataGridView);
                dataGridView.Rows.Add(row);
            }
			this.SetNameColumnWidth(dataGridView, nameColumnWidth, autoNameColumnWidth);
        }
		/// <summary>
		/// Zajistí nastavení šířky sloupce Name
		/// </summary>
		/// <param name="dataGridView"></param>
		/// <param name="nameColumnWidth"></param>
		/// <param name="autoNameColumnWidth"></param>
		protected void SetNameColumnWidth(DataGridView dataGridView, int nameColumnWidth, bool autoNameColumnWidth)
		{
			if (nameColumnWidth > 0)
				dataGridView.Columns[0].Width = nameColumnWidth;
			else if (autoNameColumnWidth)
			{
				dataGridView.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
				dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
				dataGridView.Columns[0].MinimumWidth = 200;
			}
		}
		/// <summary>
		/// Nastaví property Gridu tak, aby korektně zobrazoval ColorList
		/// </summary>
		/// <param name="dataGridView"></param>
		protected void SetProperty(DataGridView dataGridView)
		{
			dataGridView.AllowUserToAddRows = false;
			dataGridView.AllowUserToDeleteRows = true;
			dataGridView.AllowUserToOrderColumns = false;
			dataGridView.AllowUserToResizeColumns = true;
			dataGridView.AllowUserToResizeRows = true;
			dataGridView.AutoGenerateColumns = false;
			dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
			dataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
			dataGridView.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
			dataGridView.EditMode = DataGridViewEditMode.EditProgrammatically;
			dataGridView.MultiSelect = false;
			dataGridView.RowHeadersWidth = 23;
			dataGridView.ScrollBars = ScrollBars.Both;
			dataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;
			dataGridView.StandardTab = true;
		}
		#endregion
		#region Podpora vizuální editace - tvorba klonu (Get) a vstup dat z klonu (Set)
		/// <summary>
		/// Obsahuje (get vytvoří, a set akceptuje) kopii datového objektu ColorList, 
		/// který slouží jako datová vrstva pro vizuální editaci.
		/// </summary>
        [PersistingEnabled(false)]
        public Components.ColorList Clone
		{
			get { return this._GetClone(); }
			set { this._SetClone(value); }
		}
		/// <summary>
		/// Vytvoří a vrátí objekt ColorList
		/// </summary>
		/// <returns></returns>
		private ColorList _GetClone()
		{
			ColorList visual = (ColorList)this.MemberwiseClone();
			visual.ColorItems = new Dictionary<string, ColorItem>();
			foreach (KeyValuePair<string, ColorItem> item in this.ColorItems)
				visual.ColorItems.Add(item.Key, item.Value.GetClone(visual));

			return visual;
		}
		/// <summary>
		/// Převezme daný seznam ColorList a vloží jej do své paměti
		/// </summary>
		/// <param name="value"></param>
		private void _SetClone(ColorList value)
		{
			if (value == null) return;

			this.ColorItems = new Dictionary<string, ColorItem>();
			if (value.ColorItems != null)
			{
				foreach (KeyValuePair<string, ColorItem> kvp in value.ColorItems)
					this.ColorItems.Add(kvp.Key, kvp.Value.GetClone(this));
			}

			this.DefaultItemColor = value.DefaultItemColor;
			this.EmptyColumnCount = value.EmptyColumnCount;
			this.VariationEnabled = value.VariationEnabled;
			this.VariationInterval = value.VariationInterval;
			this.VariationCount = value.VariationCount;
		}
        /// <summary>
        /// Event vyvolaný po změně barev
        /// </summary>
        public event EventHandler ColorChanged;
        protected virtual void OnColorChanged()
        {
            if (this.ColorChanged != null)
                this.ColorChanged(this, EventArgs.Empty);
        }
		/// <summary>
		/// Vrátí klon listu, obsahující barevné položky pro daný klíč a jeho nadřízené klíče.
		/// </summary>
		/// <param name="key">Hledaný klíč</param>
		/// <returns></returns>
		public Components.ColorList GetSubset(string key)
		{
			ColorList visual = (ColorList)this.MemberwiseClone();
			visual.ColorItems = new Dictionary<string, ColorItem>();

			List<string> keys = SplitKey(key, SplitArrayDirect.FromGlobal);
			foreach (string keyOne in keys)
			{
				string keyLow = ColorItem.GetKey(keyOne);
				ColorItem item;
				if (!this.ColorItems.TryGetValue(keyLow, out item))
					item = new ColorItem(this, keyLow, keyOne);
				visual.ColorItems.Add(keyLow, item.GetClone(visual));
			}

			return visual;
		}
		/// <summary>
		/// Metoda vezme daný seznam (colorList) a jeho obsah přidá do své vlastní evidence.
		/// Nové klíče přidává, existující klíče aktualizuje podle hodnoty replace
		/// </summary>
		/// <param name="colorList">Objekt, který přináší vstupující data</param>
		/// <param name="itemMode">Režim přidávání nových položek (klíč)</param>
		/// <param name="colorMode">Režim přidávání barev do existujícího klíče, uplatní se pouze v případě kdy je jako režim (itemMode) zadán AppendMode.Merge</param>
		public void AppendSubset(Components.ColorList colorList, AppendMode itemMode, AppendMode colorMode)
		{
			if (colorList == null) return;
			if (colorList.ColorItems != null)
			{
				foreach (KeyValuePair<string, ColorItem> kvp in colorList.ColorItems)
				    this._Append(kvp.Key, kvp.Value, itemMode, colorMode);
                this.OnColorChanged();
			}
		}

		/// <summary>
		/// Režim slučování položek
		/// </summary>
		public enum AppendMode
		{
			/// <summary>
			/// Stávající položky zahodit, místo nich vložit položky příchozí
			/// </summary>
			Replace,
			/// <summary>
			/// Stávající položky sloučit s položkami příchozími tak, aby ve výsledku existovaly jak hodnoty původní, tak nově zadané
			/// </summary>
			Merge,
			/// <summary>
			/// Pokud pro daný klíč existuje stávající položka, pak ji ponechat v současném stavu - novou položku nepřidávat.
			/// </summary>
			Leave,
            /// <summary>
            /// Pokud pro daný klíč existuje stávající položka, pak ohlásí chybu (v daném režimu nesmí nastat)
            /// </summary>
            Error
		}
		#endregion
		#region Testovací objekt
		internal static ColorList TestList
        {
            get
            {
                ColorList test = new ColorList();
                test.Add("Grid.BackColor", "Podkladová barva", Color.LightGray, Color.LightGreen);
                test.Add("Grid.ForeColor", "Barva písma", Color.DarkGray, Color.DarkGreen, Color.Black);
                test.Add("Element.Cowley", "Element Cowley", Color.Yellow, Color.DarkGreen, Color.BlueViolet, Color.ForestGreen, Color.NavajoWhite, Color.Moccasin);
                test.Add("Element.Cowley", "Element Instance.Update", Color.Red);
                test.Add("Element.Cowley", "Element Instance.Retrieve", Color.Green, Color.LightGray, Color.Lime);
                return test;
            }
        }
        #endregion
        #region Konfigurace - reset, import, export, XML persistence
        /// <summary>
        /// Zajistí přípravu objektu this k práci.
        /// Načte do sebe data z konfigurace + doplní hodnoty z objektů, které jsou IColorDeclarator.
        /// </summary>
        internal void PrepareColors()
        {
            this.Clear();

            // Nejprve načtu konfiguraci z uloženého souboru (pokud existuje):
            if (this.ConfigFileExists)
                this.PresetLoadConfig();

            // Potom doplním položky deklarované objekty 
            this.PresetDefault();
        }
        /// <summary>
        /// Pokud existuje soubor (this.ConfigFile), pak jej do sebe načte.
        /// </summary>
        /// <returns></returns>
        internal bool PresetLoadConfig()
        {
            if (!this.ConfigFileExists)
                return false;

            this.PresetImport(this.ConfigFile);
            return true;
        }
        /// <summary>
        /// Naplní do sebe defaultní barvy, které vygenerují objekty typu IColorDeclarator.
        /// Jde o Pluginy, které 
        /// </summary>
        /// <returns></returns>
        internal bool PresetDefault()
        {
            // Defaultní barva:
            this.Append(this.DefaultItemName, this.DefaultItemColor);

            // Barvy deklaruje každý objekt, který je používá.
            // Tedy: každý objekt, který generuje elementy, do nich taky vkládá informaci o jejich barvě = jejich ColorGroup.
            // Takový objekt by měl tedy deklarovat i konkrétní barvy pro konkrétní ColorGroup.
            // Dostává k tomu šanci skrze interface IColorDeclarator (což je Plugin):
            // Kterýkoli objekt (třída), která informuje o tom, že je IColorDeclarator, je v tuto chvíli (za pár řádku) zavolána, 
            // aby svoje deklarace barev vepsala do ColorListu:

            IEnumerable<IColorDeclarator> declarators = Steward.GetServiceObjectList<IColorDeclarator>(true);
            foreach (IColorDeclarator declarator in declarators)
                declarator.ColorDeclare(new ColorDeclaratorArgs(this));

            return true;
        }
        /// <summary>
        /// Pokud je zadán soubor (this.ConfigFile), pak do něj uloží svoje data.
        /// </summary>
        /// <returns></returns>
        internal bool PresetSaveConfig()
        {
            if (!this.ConfigFileValid)
                return false;

            this.PresetExport(this.ConfigFile);
            return true;
        }
        /// <summary>
        /// Dovolí uživateli naimportovat soubor podle jeho výběru
        /// </summary>
        /// <returns></returns>
        internal bool PresetImport()
        {
            string path = Steward.AppConfig.LastExportImportPath;
            string file = "";
            if (!SystemFileDialog.GetExistingFile(ref file, ref path, "Config files (*.xml)|*.xml|All files (*.*)|*.*", ".xml", "Vyberte soubor s konfigurací barev"))
                return false;
            Steward.AppConfig.LastExportImportPath = path;

            this.PresetImport(file);
            return true;
        }
        /// <summary>
        /// Naimportuje do sebe data z daného XML souboru.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        internal bool PresetImport(string fileName)
        {
            PersistArgs args = new PersistArgs() { XmlFile = fileName };
			try
			{
				Persist.LoadTo(args, this);
			}
			catch (Exception exc)
			{
				Dialog.ShowError(exc, "Chyba při načítání dat ze souboru.");
			}

            return true;
        }
        /// <summary>
        /// Vyexportuje ze sebe data do souboru, který si zvolí uživatel
        /// </summary>
        internal bool PresetExport()
        {
            string path = Steward.AppConfig.LastExportImportPath;
            string file = "";
            if (!SystemFileDialog.GetOutputFile(ref file, ref path, "Config files (*.xml)|*.xml|All files (*.*)|*.*", ".xml", "Vyberte soubor s konfigurací barev"))
                return false;
            Steward.AppConfig.LastExportImportPath = path;

            return this.PresetExport(file);
        }
        /// <summary>
        /// Vyexportuje ze sebe data do daného souboru.
        /// </summary>
        internal bool PresetExport(string fileName)
        {
            PersistArgs args = new PersistArgs() { XmlFile = fileName };
			try
			{
				Persist.Serialize(this, args);
			}
			catch (Exception exc)
			{
				Dialog.ShowError(exc, "Chyba při ukládání dat do souboru.");
			}
			return System.IO.File.Exists(fileName);
        }
        /// <summary>
        /// Tuto property vidí XML persistor, a provádí její persistenci (namísto property .
        /// </summary>
        [PropertyName("ColorItems")]
        private List<ColorItem> ColorValues
        {
            get { return this._GetColorItems(); }
            set { this._SetColorItems(value); }
        }
        /// <summary>
        /// Vrátí seznam (List) prvků ColorItem, který je možno serializovat.
		/// Obsahuje pouze položky, které mají barvy (ContainColors).
        /// </summary>
        /// <returns></returns>
        private List<ColorItem> _GetColorItems()
        {
            return new List<ColorItem>(this.ColorItems.Values.Where(i => i.ContainColors));
        }
        /// <summary>
        /// Načte do sebe položky z dodaného Listu
        /// </summary>
        /// <param name="list"></param>
        private void _SetColorItems(List<ColorItem> list)
        {
            this.ColorItems = new Dictionary<string, ColorItem>();
            if (list != null)
            {
                foreach (ColorItem item in list)
                {
					if (!String.IsNullOrEmpty(item.Key) && item.ContainColors)
                    {
                        string keyLow = ColorItem.GetKey(item.Key);
                        if (!this.ColorItems.ContainsKey(keyLow))
                            this.ColorItems.Add(keyLow, item.GetClone(this));
                    }
                }
            }
        }
        #endregion
    }
    #endregion
    #region class ColorItem : Položka barevného listu = jeden řádek = barevná sada (název + soupis barev). Datová vrstva.
    /// <summary>
    /// Položka barevného listu = jeden řádek = barevná sada (název + soupis barev). Datová vrstva, ekvivalent vizuálního objektu ColorRow.
    /// </summary>
    public class ColorItem
    {
        #region Konstrukce a property
		/// <summary>
		/// Privátn konstruktor pro XML persistenci
		/// </summary>
		private ColorItem() { }
		public ColorItem(ColorList parent, string key)
		{
			this._Fill(parent, key, GetName(key), null);
		}
        public ColorItem(ColorList parent, string key, string name)
        {
			this._Fill(parent, key, name, null);
        }
        public ColorItem(ColorList parent, string key, string name, IEnumerable<Color> colors)
        {
			this._Fill(parent, key, name, colors);
		}
		public override string ToString()
		{
			string text = this.Name;
			string sep = ": ";
			foreach (Color c in this.Colors)
			{
				text += sep + Convertor.ColorToString(c);
				sep = ", ";
			}
			return text;	 
		}
		/// <summary>
		/// Přidá do sebe další barvy (pokud v našem seznamu ještě nejsou)
		/// </summary>
		/// <param name="colors"></param>
		internal void Merge(IEnumerable<System.Drawing.Color> colors)
		{
			if (colors == null) return;
			foreach (Color color in colors)
			{
				if (!this.Colors.Exists(c => ColorIsEqual(c, color)))
					this.Colors.Add(color);
			}
		}
		/// <summary>
		/// Vloží do sebe nový seznam barev, stávající zahodí.
		/// </summary>
		/// <param name="colors"></param>
		internal void SetColors(IEnumerable<System.Drawing.Color> colors)
		{
			if (colors == null)
				this.Colors = new List<System.Drawing.Color>();
			else
				this.Colors = new List<System.Drawing.Color>(colors);
		}
		private void _Fill(ColorList parent, string key, string name, IEnumerable<Color> colors)
		{
			this.Parent = parent;
			this.Key = GetKey(key);
			this.Name = (String.IsNullOrEmpty(name) ? key : name);
			if (colors == null)
	            this.Colors = new List<Color>();
			else
				this.Colors = new List<Color>(colors);
        }
		/// <summary>
		/// Zkontroluje klíč Key a vrátí jej Trim().ToLower();
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		internal static string GetKey(string key)
		{
			if (String.IsNullOrEmpty(key))
				throw new ArgumentException("ColorList: parameter \"key\" cannot be null or empty.");
			return key.Trim().ToLower();
		}
		/// <summary>
		/// Vrátí jméno odvozené z klíče
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		internal static string GetName(string key)
		{
			if (String.IsNullOrEmpty(key)) return "";
			if (key != key.ToLower()) return key;         // Pokud vstupní klíč není uveden v malých písmenech, pak Name = key
			string name = "";
			bool toUpper = true;
			foreach (char c in key)
			{
				string s = c.ToString();
				if (toUpper) s = s.ToUpper();
				toUpper = (c == '.');
				name += s;
			}
			return name;
		}
		/// <summary>
		/// Vrátí true, pokud dané dvě barvy mají shodnou barvu.
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		internal static bool ColorIsEqual(Color a, Color b)
		{
			return (a.A == b.A &&
					a.R == b.R &&
					a.G == b.G &&
					a.B == b.B);
		}
		/// <summary>
		/// Komparátor (pro třídění) podle hodnoty Name, StringComparison.CurrentCultureIgnoreCase
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static int CompareByName(ColorItem a, ColorItem b)
		{
			if (a == null && b == null) return 0;
			if (a == null) return -1;
			if (b == null) return 1;
			return String.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase);
		}
		/// <summary>
        /// Parent = seznam barev
        /// </summary>
        [PersistingEnabled(false)]
		public ColorList Parent { get; private set; }
        /// <summary>
        /// Klíč = určeno pro jednoznačný název řádku (barevné sady)
        /// </summary>
        public string Key { get; private set; }
        /// <summary>
        /// Jméno = určeno pro zobrazování
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Počet barev v tomto prvku
        /// </summary>
        public int ColorCount { get { return (this.Colors == null ? 0 : this.Colors.Count); } }
		/// <summary>
		/// Příznak, že obsahuje nějaké barvy, které nejsou IsEmpty
		/// </summary>
		public bool ContainColors
		{
			get
			{
				if (this.ColorCount <= 0)
					return false;
				return (this.Colors.Exists(c => !c.IsEmpty));
			}
		}
        /// <summary>
        /// Sada barev
        /// </summary>
        public List<Color> Colors { get; private set; }
        /// <summary>
        /// Reference na řádek gridu, kde je tato položka (sada barev) zobrazena
        /// </summary>
        [PersistingEnabled(false)]
        internal ColorGridRow DataGridRow
        {
            get { return ((this._DataGridRowRef != null && this._DataGridRowRef.IsAlive) ? this._DataGridRowRef.Target as ColorGridRow : null); }
            set { this._DataGridRowRef = new WeakReference(value); }
        }
        private WeakReference _DataGridRowRef;
        /// <summary>
        /// Reference na datagrid, kde je tato položka (sada barev) zobrazena.
        /// Bylo by možno jej najít i jako this.DataGridRow.DataGridView, ale ne v době tvorby prvku - ale až po jeho přidání do Gridu, což je někdy pozdě. Viz this.CheckColumns()
        /// </summary>
        [PersistingEnabled(false)]
        internal DataGridView DataGridView
        {
            get { return ((this._DataGridViewRef != null && this._DataGridViewRef.IsAlive) ? this._DataGridViewRef.Target as DataGridView : null); }
            set { this._DataGridViewRef = new WeakReference(value); }
        }
        private WeakReference _DataGridViewRef;
        #endregion
        #region Generování DataGridViewRow (a Columns, a vnitřních Cells)
        /// <summary>
        /// Vrátí řádek pro tento set barev (this), zajistí přítomnost potřebných sloupců v Gridu.
        /// Řádek obsahuje všechny potřebné buňky (Cells) a je zajištěna přítomnost potřebných Columns v daném Gridu
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <returns></returns>
        public DataGridViewRow GetDataGridRow(DataGridView dataGridView)
        {
            ColorGridRow row = new ColorGridRow(this);
            this.DataGridRow = row;
            this.DataGridView = dataGridView;

            this.CheckColumns();

            row.Cells.Add(this.GetNameCell());
            for (int i = 0; i < (this.ColorCount + 1); i++)
                row.Cells.Add(this.GetColorCell());

            this.PrepareColorRow();

            return row;
        }
        /// <summary>
        /// Vrátí buňku (Cell) pro zobrazení názvu barevné sady (text do prvního sloupce)
        /// </summary>
        /// <returns></returns>
        protected DataGridViewTextBoxCell GetNameCell()
        {
            DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell();
            cell.Value = this.Name;
            cell.ValueType = typeof(string);
            cell.Style = this.Parent.NameCellStyle;
            return cell;
        }
        /// <summary>
        /// Vrátí buňku (Cell) pro zobrazení barvy.
        /// </summary>
        /// <returns></returns>
        protected DataGridViewCell GetColorCell()
        {
            ColorGridCell cell = new ColorGridCell();
            return cell;
        }
        /// <summary>
        /// Zajistí, že v Gridu budou existovat sloupce v daném počtu (celkem)
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <param name="colorCount"></param>
        protected void CheckColumns()
        {
            DataGridView dataGridView = this.DataGridView;
            if (dataGridView == null) return;

            int columnCount = 1 + this.ColorCount + this.Parent.EmptyColumnCount;       // Celkem počet sloupců: 1=Name + ColorCount + rezerva (v rozsahu 1÷8).
            for (int c = 0; c < columnCount; c++)
            {
                if (dataGridView.Columns.Count <= c)
                {
                    if (c == 0)
                        dataGridView.Columns.Add(GetNameColumn(dataGridView));
                    else
                        dataGridView.Columns.Add(GetColorColumn(dataGridView, (c - 1)));
                }
            }
        }
        /// <summary>
        /// Vrátí sloupec (Column) pro zobrazování názvu barevné sady (první sloupec)
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <returns></returns>
        protected DataGridViewColumn GetNameColumn(DataGridView dataGridView)
        {
            DataGridViewColumn col = new DataGridViewColumn();
            col.CellTemplate = GetNameCell();
            col.HeaderText = "Název položky";
            col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
            col.MinimumWidth = 100;
            col.Name = "Name";
            col.ReadOnly = true;
            col.Resizable = DataGridViewTriState.True;
            col.SortMode = DataGridViewColumnSortMode.Automatic;
            col.Visible = true;
            col.Width = 200;
            return col;
        }
        /// <summary>
        /// Vrátí sloupec (Column) pro zobrazování barvy (druhý a každý další sloupec)
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <param name="colIdx"></param>
        /// <returns></returns>
        protected DataGridViewColumn GetColorColumn(DataGridView dataGridView, int colIdx)
        {
            DataGridViewColumn col = new DataGridViewColumn();
            col.CellTemplate = GetColorCell();
            col.HeaderText = "";
            col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
            col.MinimumWidth = 20;
            col.Name = "Color" + colIdx.ToString();
            col.ReadOnly = false;
            col.Resizable = DataGridViewTriState.False;
            col.SortMode = DataGridViewColumnSortMode.NotSortable;
            col.Visible = true;
            col.Width = 36;
            return col;
        }
        #endregion
        #region Modifikace seznamu barev
        /// <summary>
        /// Přidá prázdnou barvu
        /// </summary>
        public void AddColor()
        {
            this.Colors.Add(Color.Empty);
            this.PrepareColorRow();
        }
        /// <summary>
        /// Přidá zadanou barvu
        /// </summary>
        public void AddColor(Color color)
        {
            this.Colors.Add(color);
            this.PrepareColorRow();
        }
        /// <summary>
        /// Vloží danou barvu do seznamu na dané místo.
        /// </summary>
        /// <param name="color"></param>
        /// <param name="index"></param>
        internal void SetColor(Color color, int index)
        {
            if (index >= 0 && index < this.ColorCount)
                this.Colors[index] = color;
            else
                this.Colors.Add(color);

            this.PrepareColorRow();
        }
        /// <summary>
        /// Odebere barvu na daném indexu
        /// </summary>
        /// <param name="colorIndex"></param>
        internal void RemoveColorAt(int colorIndex)
        {
            if (colorIndex >= 0 && colorIndex < this.Colors.Count)
            {
                this.Colors.RemoveAt(colorIndex);
                this.PrepareColorRow();
            }
        }
        /// <summary>
        /// Zajistí, že ve vizuálním řádku budou korektně přítomny buňky (ColorCell) pro všechny barvy + 1 navíc (AddNew)
        /// </summary>
        internal void PrepareColorRow()
        {
            ColorGridRow row = this.DataGridRow;
            if (row == null) return;

            this.CheckColumns();

            int colorCount = this.ColorCount;
            int cellCount = row.Cells.Count;
            for (int cellIndex = 1; cellIndex < cellCount; cellIndex++)
            {
                int colorIndex = cellIndex - 1;
                ColorGridCell cell = row.Cells[cellIndex] as ColorGridCell;
                if (cell == null)
                { }
                if (colorIndex >= 0 && colorIndex < colorCount)
                {   // Tato buňka má zobrazovat konkrétní barvu:
                    cell.SetProperty(this, colorIndex, this.Colors[colorIndex], ColorGridCell.CellEditMode.EditOrDelete);
                }
                else if (colorIndex == colorCount)
                {
                    cell.SetProperty(this, -1, Color.Empty, ColorGridCell.CellEditMode.AddNew);
                }
                else
                {
                    cell.SetProperty(this, -1, Color.Empty, ColorGridCell.CellEditMode.None);
                }
            }
        }
        #endregion
        #region Nalezení konkrétní barvy pro dané číslo Int32
        /// <summary>
        /// Vrátí jednu barvu ze sady, odpovídající danému číslu Integer.
		/// Anebo ji variuje sám, pokud je v sadě jen jedna.
        /// </summary>
        /// <param name="colorSet"></param>
        /// <param name="objectId"></param>
        /// <returns></returns>
		internal System.Drawing.Color GetColor(int objectId)
		{
			if (!this.ContainColors)
				return this.Parent.DefaultItemColor;

			int length = this.Colors.Count;
			
			// Pokud máme víc než jednu barvu, vrátím exaktní barvu odpovídající číslu Int32:
			if (length > 1)
            {
                int index = objectId % length;          // Index barvy = číslo objektu až do počtu prvků pole, a pak zase od 0
				return this.Colors[index];
            }
			return ColorList.GetColorVariation(this.Colors[0], objectId, this.Parent.VariationInterval);
        }
		#endregion
		#region Podpora vizuální editace - tvorba klonu (Get) a vstup dat z klonu (Set)
		/// <summary>
		/// Vytvoří a vrátí objekt ColorList
		/// </summary>
		/// <returns></returns>
		public ColorItem GetClone(ColorList parent)
		{
			ColorItem visual = (ColorItem)this.MemberwiseClone();
			visual.Parent = parent;
			visual.Colors = new List<System.Drawing.Color>(this.Colors);
			return visual;
		}
		/// <summary>
		/// Převezme daný seznam ColorList a vloží jej do své paměti
		/// </summary>
		/// <param name="value"></param>
		public void SetClone(ColorItem value)
		{
			if (value == null) return;
			if (value.Colors == null)
				this.Colors = new List<System.Drawing.Color>();
			else
				this.Colors = new List<System.Drawing.Color>(value.Colors);
		}
	    #endregion
	}
    #endregion
    #region class ColorListPanel : Panel, který zobrazuje barvy (objekt třídy ColorGridView) a vlastnosti (objekt třídy ColorPropertyPanel) pro daný ColorList
    /// <summary>
    /// ColorListPanel : Panel, který zobrazuje barvy (objekt třídy ColorGridView) a vlastnosti (objekt třídy ColorPropertyPanel) pro daný ColorList
    /// </summary>
    internal class ColorListPanel : DPanel
    {
        #region Konstrukce
        public ColorListPanel()
        {
            this.Init();
        }
        protected void Init()
        {
            this._ColorGrid = new ColorGridView() { Dock = DockStyle.Fill, TabIndex = 0, TabStop = true };
            this._ColorProperty = new ColorPropertyPanel() { Dock = DockStyle.Bottom, BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D, TabIndex = 1, TabStop = true };

            this.Controls.Add(this._ColorGrid);
            this.Controls.Add(this._ColorProperty);

            this._ColorGrid.RowEnter += new DataGridViewCellEventHandler(_ColorGrid_RowEnter);
			this._ColorProperty.ActionDataLoad += new EventHandler(_ColorProperty_ActionDataLoad);
			this._ColorProperty.ActionDataSave += new EventHandler(_ColorProperty_ActionDataSave);
        }
        void _ColorGrid_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0 && e.RowIndex < this._ColorGrid.Rows.Count)
			{
                DataGridViewRow row = this._ColorGrid.Rows[e.RowIndex];
				if (row is ColorGridRow)
					this._ShowColorProperties(row as ColorGridRow);
			}
        }
		/// <summary>
		/// Panel ColorProperty bude ukládat data z vizuální vrstvy do datové a z ní pak do souboru.
		/// Před tím je třeba uložit další data z vizuální do datové vrstvy, což zajišťuje tento event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void _ColorProperty_ActionDataSave(object sender, EventArgs e)
		{
		}
		/// <summary>
		/// V panelu ColorProperty došlo k načtení dat (ze souboru) do datového objektu, data se mají zobrazit v Gridu.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void _ColorProperty_ActionDataLoad(object sender, EventArgs e)
		{
			this._ColorGrid.ColorList = this._ColorList;         // Grid se znovu napojí na ColorList = převezme si řádky a barvy a napojí se na položky
		}
		/// <summary>
        /// Zobrazí v okně vlastností barev data z aktuálního řádku
        /// </summary>
        /// <param name="colorGridRow"></param>
        private void _ShowColorProperties(ColorGridRow colorGridRow)
        {
            if (colorGridRow != null && colorGridRow.ColorItem != null && colorGridRow.ColorItem.ColorCount > 0)
                this._ColorProperty.BaseColor = colorGridRow.ColorItem.Colors[0];
            else
                this._ColorProperty.BaseColor = Color.Empty;
        }
        private ColorGridView _ColorGrid;
        private ColorPropertyPanel _ColorProperty;
        #endregion
        #region Property
        /// <summary>
        /// Datový objekt, na který je Grid napojen, jehož položky zobrazuje.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public ColorList ColorList
        {
            get { return this._GetColorList(); }
            set { this._SetColorList(value); }
        }
        #endregion
        #region Vizualizace dat z datového objektu, a jejich následné ukládání zpátky
        private ColorList _ColorList;
        /// <summary>
        /// Metoda zajistí posbírání dat z vizuální vrstvy do vrstvy datové, do objektu this._ColorList
        /// </summary>
        /// <returns></returns>
        private ColorList _GetColorList()
        {
            var x = this._ColorGrid.ColorList;         // Grid zajistí vložení dat z vizuální do datové vrstvy a tu vrátí. O vrácený objekt nestojíme, důležité je sesbírání dat. ...
            var y = this._ColorProperty.ColorList;     //  ... Objekt sdílíme v naší proměnné this._ColorList, kterou vracíme.
            return this._ColorList;
        }
        /// <summary>
        /// Metoda zajistí napojení tohoto objektu na datový objekt: převezme do vizuální vrstvy data z datové vrstvy
        /// </summary>
        /// <param name="value"></param>
        private void _SetColorList(ColorList value)
        {
			this._ColorList = value;
			this._ColorGrid.ColorList = value;         // Grid se napojí na ColorList = převezme si řádky a barvy a napojí se na položky
            this._ColorProperty.ColorList = value;     // Property se načtou z ColorListu
        }
        #endregion
    }
    #endregion
    #region class ColorGridView : Vizuální Grid, který zobrazuje položky z ColorListu
    /// <summary>
    /// ColorGridView : Vizuální Grid, který zobrazuje položky z ColorListu
    /// </summary>
    internal class ColorGridView : DataGridView
    {
        /// <summary>
        /// Datový objekt, na který je Grid napojen, jehož položky zobrazuje.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public ColorList ColorList
        {
            get { return this._GetColorList(); }
            set { this._SetColorList(value); }
        }
        #region Vizualizace dat z datového objektu, a jejich následné ukládání zpátky
        private ColorList _ColorList;
        /// <summary>
        /// Metoda zajistí posbírání dat z vizuální vrstvy do vrstvy datové, do objektu this._ColorList
        /// </summary>
        /// <returns></returns>
        private ColorList _GetColorList()
        {
 	        // Data se editují v Gridu, který obsahuje přímé vazby do objektu ColorList, takže editovaná data už v objektu jsou. Není třeba nic přenášet.
            return this._ColorList;
        }
        /// <summary>
        /// Metoda zajistí napojení tohoto objektu na datový objekt: převezme do vizuální vrstvy data z datové vrstvy
        /// </summary>
        /// <param name="value"></param>
        private void _SetColorList(ColorList value)
        {
            this._ColorList = value;
            if (value != null)
                this._ColorList.FillGridView(this, true);
        }
		#endregion
    }
    #endregion
    #region class ColorPropertyPanel : Panel, který zobrazuje vlastnosti ColorListu kromě barev (řízení chování)
    /// <summary>
    /// ColorPropertyPanel : Panel, který zobrazuje vlastnosti ColorListu kromě barev (řízení chování)
    /// </summary>
    internal class ColorPropertyPanel : DPanel
    {
        #region Konstrukce
        public ColorPropertyPanel()
        {
            this.Init();
        }
        protected void Init()
        {
            // Controly:
            this._VariationEnable = new System.Windows.Forms.CheckBox() { Bounds = new Rectangle(3, 3, 167, 45), TabIndex = 0, TabStop = true };
            this._VariationInterval = new System.Windows.Forms.TrackBar() { Bounds = new Rectangle(176, 3, 125, 45), TabIndex = 1, TabStop = true };
            this._VariationCnt = new System.Windows.Forms.Panel() { Bounds = new Rectangle(307, 0, 80, 60), TabIndex = 2, TabStop = true };
            this._ColorSample = new ColorSamplePanel() { Bounds = new Rectangle(393, -2, 111, 60), TabIndex = 3, TabStop = false, BackColor = SystemColors.ControlLight };
            this._Line1 = new HLine() { Bounds = new Rectangle(3, 48, 505, 24), Text = "Export / Import barevného nastavení", FontBold = true };
            this._CfgClearBtn = new Button() { Bounds = new Rectangle(100, 67, 120, 32), Text = "Výchozí", Image = PicLibraryColorList.DocNew_FromFile, TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText, TabIndex = 4, TabStop = true };
            this._CfgImportBtn = new Button() { Bounds = new Rectangle(223, 67, 120, 32), Text = "Import", Image = PicLibraryColorList.DocOpen_FromFile, TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText, TabIndex = 5, TabStop = true };
            this._CfgExportBtn = new Button() { Bounds = new Rectangle(346, 67, 120, 32), Text = "Export", Image = PicLibraryColorList.DocSave_FromFile, TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText, TabIndex = 6, TabStop = true };

            // this
            this.BackColor = System.Drawing.SystemColors.Control;
            this.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
            this.Controls.Add(this._ColorSample);
            this.Controls.Add(this._VariationInterval);
            this.Controls.Add(this._VariationCnt);
            this.Controls.Add(this._VariationEnable);
            this.Controls.Add(this._CfgClearBtn);
            this.Controls.Add(this._CfgImportBtn);
            this.Controls.Add(this._CfgExportBtn);
            this.Controls.Add(this._Line1);
            this.Name = "_ColorProperty";
            this.Size = new System.Drawing.Size(505, 105);

            // _VariationEnable
            this._VariationEnable.AutoSize = false;
            this._VariationEnable.Text = "Povolit barevné variace pro jednobarevné položky";
            this._VariationEnable.UseVisualStyleBackColor = true;
            this._VariationEnable.CheckedChanged += new EventHandler(_VariationEnable_CheckedChanged);

            // _VariationSize
            this._VariationInterval.LargeChange = 6;
            this._VariationInterval.Maximum = 48;
            this._VariationInterval.TickFrequency = 3;
            this._VariationInterval.TickStyle = System.Windows.Forms.TickStyle.Both;
            this._VariationInterval.ValueChanged += new EventHandler(_VariationSize_ValueChanged);

            // _VariationCnt
            this._VariationCnt3 = new System.Windows.Forms.RadioButton() { AutoSize = true, Location = new Point(3, 2), TabIndex = 0, TabStop = true, Text = "3 barvy", UseVisualStyleBackColor = true };
            this._VariationCnt6 = new System.Windows.Forms.RadioButton() { AutoSize = true, Location = new Point(3, 19), TabIndex = 1, TabStop = true, Text = "6 barev", UseVisualStyleBackColor = true };
            this._VariationCnt9 = new System.Windows.Forms.RadioButton() { AutoSize = true, Location = new Point(3, 36), TabIndex = 2, TabStop = true, Text = "9 barev", UseVisualStyleBackColor = true };
            this._VariationCnt.Controls.Add(this._VariationCnt3);
            this._VariationCnt.Controls.Add(this._VariationCnt6);
            this._VariationCnt.Controls.Add(this._VariationCnt9);

            // Eventy:
            this.SizeChanged += new EventHandler(_SizeChanged);
            this._VariationCnt3.CheckedChanged += new EventHandler(_VariationCnt_CheckedChanged);
            this._VariationCnt6.CheckedChanged += new EventHandler(_VariationCnt_CheckedChanged);
            this._VariationCnt9.CheckedChanged += new EventHandler(_VariationCnt_CheckedChanged);
            this._CfgClearBtn.Click += new EventHandler(_CfgClearBtn_Click);
            this._CfgImportBtn.Click += new EventHandler(_CfgImportBtn_Click);
            this._CfgExportBtn.Click += new EventHandler(_CfgExportBtn_Click);


            this.BaseColor = Color.LightSkyBlue;
        }
        private System.Windows.Forms.CheckBox _VariationEnable;
        private System.Windows.Forms.TrackBar _VariationInterval;
        private System.Windows.Forms.Panel _VariationCnt;
        private System.Windows.Forms.RadioButton _VariationCnt3;
        private System.Windows.Forms.RadioButton _VariationCnt6;
        private System.Windows.Forms.RadioButton _VariationCnt9;
        private ColorSamplePanel _ColorSample;
        private Button _CfgClearBtn;
        private Button _CfgImportBtn;
        private Button _CfgExportBtn;
        private HLine _Line1;
        #endregion
        #region Obsluha interních eventů
        void _SizeChanged(object sender, EventArgs e)
        {
            this.ArrangeControls();
        }
        void _VariationEnable_CheckedChanged(object sender, EventArgs e)
        {
            this._ShowColors();
        }
        void _VariationSize_ValueChanged(object sender, EventArgs e)
        {
            this._ShowColors();
        }
        void _VariationCnt_CheckedChanged(object sender, EventArgs e)
        {
            int cnt = 1;
            if (this._VariationCnt3.Checked)
                cnt = 3;
            else if (this._VariationCnt6.Checked)
                cnt = 6;
            else if (this._VariationCnt9.Checked)
                cnt = 9;
            this._VariationCount = cnt;
            this._ShowColors();
        }
        void _CfgClearBtn_Click(object sender, EventArgs e)
        {
            if (this.ColorList.PresetDefault())
            {
                this.DataLoad();
                this.OnActionDataLoad();
            }
        }
        void _CfgImportBtn_Click(object sender, EventArgs e)
        {
            if (this.ColorList.PresetImport())
            {
                this.DataLoad();
                this.OnActionDataLoad();
            }
        }
        void _CfgExportBtn_Click(object sender, EventArgs e)
        {
            this.OnActionDataSave();
            this.DataSave();
            bool exported = this.ColorList.PresetExport();
			if (exported)
				Dialog.ShowInfo("Data byla uložena do souboru.");
        }
        protected void ArrangeControls()
        {
            Size clientSize = this.ClientSize;
            this._ColorSample.Left = clientSize.Width - this._ColorSample.Width - 3;
            this._Line1.Width = clientSize.Width - this._Line1.Left;
        }
        protected virtual void OnActionDataLoad()
        {
            if (this.ActionDataLoad != null)
                this.ActionDataLoad(this, EventArgs.Empty);
        }
        protected virtual void OnActionDataSave()
        {
            if (this.ActionDataSave != null)
                this.ActionDataSave(this, EventArgs.Empty);
        }
        /// <summary>
        /// Zobrazí vzorky barev
        /// </summary>
        private void _ShowColors()
        {
            int i = this.VariationInterval;
            Color c = this.BaseColor;
            if (this.VariationEnable)
            {
                switch (this.VariationCount)
                {
                    case 1:
                        this._ColorSample.Colors = new Color[,]
						{
							{ c }
						};
                        break;
                    case 3:
                        this._ColorSample.Colors = new Color[,]
						{
							{ ColorList.GetColorVariation(c, 1, i), ColorList.GetColorVariation(c, 0, i), ColorList.GetColorVariation(c, 2, i) }
						};
                        break;
                    case 6:
                        this._ColorSample.Colors = new Color[,]
						{
							{ ColorList.GetColorVariation(c, 1, i), ColorList.GetColorVariation(c, 0, i), ColorList.GetColorVariation(c, 2, i) },
							{ ColorList.GetColorVariation(c, 3, i), ColorList.GetColorVariation(c, 4, i), ColorList.GetColorVariation(c, 5, i) }
						};
                        break;
                    case 9:
                    default:
                        this._ColorSample.Colors = new Color[,]
						{
							{ ColorList.GetColorVariation(c, 1, i), ColorList.GetColorVariation(c, 2, i), ColorList.GetColorVariation(c, 3, i) },
							{ ColorList.GetColorVariation(c, 4, i), ColorList.GetColorVariation(c, 0, i), ColorList.GetColorVariation(c, 5, i) },
							{ ColorList.GetColorVariation(c, 6, i), ColorList.GetColorVariation(c, 7, i), ColorList.GetColorVariation(c, 8, i) }
						};
                        break;
                }
            }
            else
            {
                this._ColorSample.Colors = new Color[,] { { c } };
            }
            this.Refresh();
        }
        #endregion
        #region Public Property a eventy
        /// <summary>
        /// Datový objekt, na který je Grid napojen, jehož položky zobrazuje.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public ColorList ColorList
        {
            get { return this._GetColorList(); }
            set { this._SetColorList(value); }
        }
        /// <summary>
        /// Hodnota povolující variace barev
        /// </summary>
        [Category("ColorListPropertyPanel")]
        [Description("Hodnota povolující variace barev")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(true)]
        public bool VariationEnable
        {
            get { return this._VariationEnable.Checked; }
            set { this._VariationEnable.Checked = value; this._ShowColors(); }
        }
        /// <summary>
        /// Rozsah barevných variant
        /// </summary>
        [Category("ColorListPropertyPanel")]
        [Description("Rozsah barevných variant (0 - 48)")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(true)]
        public int VariationInterval
        {
            get { return this._VariationInterval.Value; }
            set { this._VariationInterval.Value = (value < 0 ? 0 : (value > 48 ? 48 : value)); this._ShowColors(); }
        }
        /// <summary>
        /// Počet barevných variant: povolené hodnoty jsou: 1, 3, 6, 9. Jiné hodnoty budou ignorovány.
        /// </summary>
        [Category("ColorListPropertyPanel")]
        [Description("Počet barevných variant: povolené hodnoty jsou: 1, 3, 6, 9. Jiné hodnoty budou ignorovány.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(true)]
        public int VariationCount
        {
            get { return this._VariationCount; }
            set
            {
                if (value == 1 || value == 3 || value == 6 || value == 9)
                {
                    this._VariationCount = value;
                    switch (value)
                    {
                        case 1:
                            this._VariationCnt3.Checked = false;
                            this._VariationCnt6.Checked = false;
                            this._VariationCnt9.Checked = false;
                            break;
                        case 3:
                            this._VariationCnt3.Checked = true;
                            break;
                        case 6:
                            this._VariationCnt6.Checked = true;
                            break;
                        case 9:
                            this._VariationCnt9.Checked = true;
                            break;
                    }
                    this._ShowColors();
                }
            }
        }
        private int _VariationCount;
        /// <summary>
        /// Základní barva, kterou budeme variovat
        /// </summary>
        [Category("ColorListPropertyPanel")]
        [Description("Základní barva, kterou budeme variovat")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(true)]
        public Color BaseColor
        {
            get { return this._BaseColor; }
            set { this._BaseColor = value; this._ShowColors(); }
        }
        private Color _BaseColor;
        /// <summary>
        /// Na tomto panelu byla vyvolána akce, která si vyžaduje nové načtení dat z datové vrstvy do vizuální (typicky po načtení konfigurace ze souboru).
        /// Tento event umožňuje okolním objektům (typicky ColorListPanel a ColorGridView), aby si poté rovněž načetly data, která zobrazují.
        /// </summary>
        [Category("ColorListPropertyPanel")]
        [Description("Základní barva, kterou budeme variovat")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        public event EventHandler ActionDataLoad;
        /// <summary>
        /// Na tomto panelu byla vyvolána akce, která si vyžaduje uložení dat z vizuální vrstvy do datové vrstvy (typicky před ukládáním konfigurace do souboru).
        /// Tento event umožňuje okolním objektům (typicky ColorListPanel a ColorGridView), aby uložily data, která zobrazují.
        /// </summary>
        [Category("ColorListPropertyPanel")]
        [Description("Základní barva, kterou budeme variovat")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        public event EventHandler ActionDataSave;
        #endregion
        #region Vizualizace dat z datového objektu, a jejich následné ukládání zpátky
        private ColorList _ColorList;
        /// <summary>
        /// Metoda zajistí napojení tohoto objektu na datový objekt: převezme do vizuální vrstvy data z datové vrstvy
        /// </summary>
        /// <param name="value"></param>
        private void _SetColorList(ColorList value)
        {
            this._ColorList = value;
            this.DataLoad();
        }
        /// <summary>
        /// Metoda zajistí posbírání dat z vizuální vrstvy do vrstvy datové, do objektu this._ColorList
        /// </summary>
        /// <returns></returns>
        private ColorList _GetColorList()
        {
            this.DataSave();
            return this._ColorList;
        }
        /// <summary>
        /// Zajistí načtení dat z datového objektu do vizuálních controlů
        /// </summary>
        protected void DataLoad()
        {
            if (this._ColorList != null)
            {
                this.VariationEnable = this._ColorList.VariationEnabled;
                this.VariationInterval = this._ColorList.VariationInterval;
                this.VariationCount = this._ColorList.VariationCount;
            }
        }
        /// <summary>
        /// Zajistí uložení dat z vizuálních controlů do datového objektu
        /// </summary>
        protected void DataSave()
        {
            if (this._ColorList != null)
            {
                this._ColorList.VariationEnabled = this.VariationEnable;
                this._ColorList.VariationInterval = this.VariationInterval;
                this._ColorList.VariationCount = this.VariationCount;
            }
        }
		#endregion
    }
    #endregion
    #region class ColorSamplePanel : Panel pro zobrazení barevných variant
    /// <summary>
    /// ColorSamplePanel : panel pro zobrazení barevných variant
    /// </summary>
    internal class ColorSamplePanel : Components.DblGraphPanel
    {
        /// <summary>
        /// Barvy zobrazené v panelu
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public Color[,] Colors
        {
            get { return _Colors; }
            set { this._Colors = value; this.Refresh(); }
        }
        private Color[,] _Colors;
        protected override void OnPaintToBuffer(object sender, PaintEventArgs e)
        {
            RectangleF area = this.ClientRectangle;
            if (this.Colors == null)
            {
                using (SolidBrush b = new SolidBrush(this.BackColor))
                {
                    e.Graphics.FillRectangle(b, area);
                }
                return;
            }
            int xc = this.Colors.GetLength(1);
            int yc = this.Colors.GetLength(0);
            float xs = area.Width / (float)xc;
            float ys = area.Height / (float)yc;
            float xd = area.Left;
            float yd = area.Top;
            for (int x = 0; x < xc; x++)
            {
                for (int y = 0; y < yc; y++)
                {
                    RectangleF r = new RectangleF(xd + (float)x * xs, yd + (float)y * ys, xs, ys);
                    Color c = this.Colors[y, x];
                    using (SolidBrush b = new SolidBrush(c))
                    {
                        e.Graphics.FillRectangle(b, r);
                    }
                }
            }
        }
    }
    #endregion
    #region class ColorGridRow : Vizuální řádek pro jednu barevnou sadu. Potomek DataGridViewRow. Váže se na data v ColorItem, která zobrazuje.
    /// <summary>
    /// ColorGridRow : Vizuální řádek pro jednu barevnou sadu. Potomek DataGridViewRow.
    /// Váže se na data v ColorItem, která zobrazuje.
    /// </summary>
    internal class ColorGridRow : DataGridViewRow
    {
        public ColorGridRow(ColorItem colorItem)
        {
            this.ColorItem = colorItem;             // Do vizuálního řádku vkládám odkaz na data.
            this.DefaultCellStyle = colorItem.Parent.NameCellStyle;
            colorItem.DataGridRow = this;           // Zde se ukládá Weak reference: datová položka může žít bez vizuální reprezentace, ale ne naopak.
        }
        public ColorItem ColorItem { get; private set; }
    }
    #endregion
    #region class ColorGridCell : Vizuální buňka pro jednu konrétní barvu. Potomek DataGridViewTextBoxCell. Váže se na Color. Umožňuje editaci.
    /// <summary>
    /// ColorGridCell : Vizuální buňka pro jednu konrétní barvu. Potomek DataGridViewCell ("soused" například DataGridViewTextBoxCell).
    /// Váže se na Color. Umožňuje editaci.
    /// </summary>
    internal class ColorGridCell : DataGridViewCell
    {
        #region Konstrukce, proměnné
        public ColorGridCell()
        {
            this.Value = "";
            this.ValueType = typeof(string);
            this.Parent = null;
            this.EditMode = CellEditMode.None;
            this.ColorValue = Color.Empty;
        }
        internal void SetProperty(ColorItem parent, int index, Color colorValue, CellEditMode editMode)
        {
            this.Parent = parent;
            this.ColorIndex = index;
            this.EditMode = editMode;
            this.ColorValue = colorValue;
        }

        private System.Drawing.Color _ColorValue;
        private bool _WithMouse;
        private bool _Focused;
        private CellAreaType _MouseDownArea;
        private List<KeyValuePair<CellAreaType, Rectangle>> _InnerAreas;
        #endregion
        #region Property, enums
        internal CellEditMode EditMode { get; private set; }
        /// <summary>
        /// Režim editace buňky
        /// </summary>
        internal enum CellEditMode
        {
            /// <summary>
            /// Nelze editovat, nelze smazat, nelze přidat
            /// </summary>
            None = 0,
            /// <summary>
            /// Lze pouze editovat, nelze smazat
            /// </summary>
            Edit,
            /// <summary>
            /// Lze editovat a nebo smazat
            /// </summary>
            EditOrDelete,
            /// <summary>
            /// Lze přidat novou položku
            /// </summary>
            AddNew
        }
        #endregion
        #region Overrides (Paint, Mouse, Focus)
        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            PaintCell(graphics, clipBounds, cellBounds, rowIndex, cellState, cellStyle, advancedBorderStyle, paintParts);
        }
        protected override void OnEnter(int rowIndex, bool throughMouseClick)
        {
            this._Focused = true;

            base.OnEnter(rowIndex, throughMouseClick);
        }
        protected override void OnLeave(int rowIndex, bool throughMouseClick)
        {
            this._Focused = false;
            base.OnLeave(rowIndex, throughMouseClick);
        }
		protected override void OnMouseEnter(int rowIndex)
		{
			this._WithMouse = true;
            this.RePaint();
			base.OnMouseEnter(rowIndex);
		}
		protected override void OnMouseLeave(int rowIndex)
		{
			this._WithMouse = false;
            this.RePaint();
			base.OnMouseLeave(rowIndex);
		}
        protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
        {
            if (this._Focused && e.Button == MouseButtons.Left)
            {
                this._MouseDownArea = this.FindCellArea(e.Location);
            }
            else
                this._MouseDownArea = CellAreaType.Cell;
            base.OnMouseDown(e);
        }
        protected override void OnMouseUp(DataGridViewCellMouseEventArgs e)
        {
            this._MouseDownArea = CellAreaType.None;
            base.OnMouseUp(e);
        }
        protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
        {
            switch (this._MouseDownArea)
            {
                case CellAreaType.None:
                case CellAreaType.Cell:
                    this.OnColorChange();
                    break;
                case CellAreaType.ButtonPlus:
                    this.OnColorAdd();
                    break;
                case CellAreaType.ButtonMinus:
                    this.OnColorDelete();
                    break;
            }
        }
        protected override void OnKeyDown(KeyEventArgs e, int rowIndex)
        {
            if (e.Control && e.KeyCode == Keys.Enter)
            {
                this.OnColorChange();
                e.Handled = true;
            }
            else if (!e.Control && e.KeyCode == Keys.Delete)
            {
                if (this.EditMode == CellEditMode.EditOrDelete)
                {
                    this.OnColorDelete();
                    e.Handled = true;
                }
            }
            base.OnKeyDown(e, rowIndex);
        }
        #endregion
        #region Kreslení buňky a jejích buttonů
        /// <summary>
        /// Zajistí vykreslení buňky. A protože nemáme Refresh(), používám RaiseCellValueChanged().
        /// </summary>
        public void RePaint()
        {
            this.RaiseCellValueChanged(new DataGridViewCellEventArgs(this.ColumnIndex, this.RowIndex));
        }
        /// <summary>
        /// Vykreslí obsah buňky (pozadí, buttony).
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="clipBounds"></param>
        /// <param name="cellBounds"></param>
        /// <param name="rowIndex"></param>
        /// <param name="cellState"></param>
        /// <param name="cellStyle"></param>
        /// <param name="advancedBorderStyle"></param>
        /// <param name="paintParts"></param>
        protected void PaintCell(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            // Aktivní místa buňky - vynulovat:
            this._InnerAreas = new List<KeyValuePair<CellAreaType, System.Drawing.Rectangle>>();

            // Pozadí buňky:
            bool isActive = (this._Focused || this._WithMouse);
            // if (this.EditMode == CellEditMode.None) isActive = false;
            if (isActive)
                this.PaintCellBackActive(graphics, cellBounds);
            else
                this.PaintCellBackNormal(graphics, cellBounds);

            // Images:
            this.PaintImages(graphics, cellBounds);

            // Buttony:
            this.PaintButtons(graphics, cellBounds);

            // Na závěr zajistím vykreslení Borderu:
            this.PaintBorderPrepareStyle(advancedBorderStyle);
            base.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
        }
        /// <summary>
        /// Vykreslí pozadí aktivní buňky
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cellBounds"></param>
        private void PaintCellBackActive(System.Drawing.Graphics graphics, System.Drawing.Rectangle cellBounds)
        {
            Color color = this.ColorValue;
            if (this.EditMode == CellEditMode.AddNew)
                color = SystemColors.Control;      //  Color.LightYellow;
            if (color.IsEmpty)
                color = SystemColors.ControlLight; // this.DataGridView.BackgroundColor;

            Color color1, color2;
            float trg = 0.5F;

            if (this.EditMode == CellEditMode.None)
            {
                color = this.OwningRow.DefaultCellStyle.BackColor;
                if (color.IsEmpty)
                    color = SystemColors.ControlLight;
                color = ColorShift(color, -16);
                ColorRange(color, out color1, out color2, 16, 16, 16);
                trg = 0.00F;
            }
            else if (this._MouseDownArea == CellAreaType.Cell)
            {
                ColorRange(color, out color1, out color2, 64, 64, 64);
                trg = 0.25F;
            }
            else
            {
                ColorRange(color, out color2, out color1, 64, 64, 64);
                trg = 0.65F;
            }
            LinearGradientMode mode = LinearGradientMode.Vertical;
            using (LinearGradientBrush lgb = new LinearGradientBrush(cellBounds, color1, color2, mode))
            {
                //lgb.SetSigmaBellShape(0.9f, 0.9f);
                lgb.SetBlendTriangularShape(trg, 1F - trg);
                graphics.FillRectangle(lgb, cellBounds);
            }

            // Klikací mapa:
            this._InnerAreas.Add(new KeyValuePair<CellAreaType, System.Drawing.Rectangle>(CellAreaType.Cell, cellBounds));
        }
        /// <summary>
        /// Vykreslí pozadí neaktivní buňky
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cellBounds"></param>
        private void PaintCellBackNormal(System.Drawing.Graphics graphics, System.Drawing.Rectangle cellBounds)
        {
            Color backColor = (!this.ColorValue.IsEmpty ? this.ColorValue : this.OwningRow.DefaultCellStyle.BackColor);
            backColor = this.ColorValue;
			if (this.ColorValue.IsEmpty)
			{
				if (this.OwningRow.Index >= 0)
					backColor = this.OwningRow.InheritedStyle.BackColor;
			}
            using (SolidBrush slb = new System.Drawing.SolidBrush(backColor))
            {
                graphics.FillRectangle(slb, cellBounds);
            }

            // Klikací mapa:
            this._InnerAreas.Add(new KeyValuePair<CellAreaType, System.Drawing.Rectangle>(CellAreaType.Cell, cellBounds));
        }
        /// <summary>
        /// Vykreslí obrázky
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cellBounds"></param>
        private void PaintImages(System.Drawing.Graphics graphics, System.Drawing.Rectangle cellBounds)
        {
            switch (this.EditMode)
            {
                case CellEditMode.AddNew:
                    if (this._WithMouse)
                        this.PaintImage(graphics, cellBounds, PicLibraryColorList.New_Cached);
                    else
                        this.PaintImage(graphics, cellBounds, PicLibraryColorList.Newb_Cached);
                    break;
            }
        }
        /// <summary>
        /// Vykreslí jeden image
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cellBounds"></param>
        /// <param name="image"></param>
        private void PaintImage(System.Drawing.Graphics graphics, System.Drawing.Rectangle cellBounds, System.Drawing.Image image)
        {
            Rectangle imgArea = Rectangle.Round(GetCenterArea(cellBounds, image.Size));
            graphics.DrawImageUnscaled(image, imgArea);
        }
        /// <summary>
        /// Vykreslí oba buttony (pokud mají být vidět).
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cellBounds"></param>
        private void PaintButtons(System.Drawing.Graphics graphics, System.Drawing.Rectangle cellBounds)
        {
            int s = 1;
            int h = cellBounds.Height - s - s;
            if (h > 13) h = 13;
            Rectangle btnArea = new System.Drawing.Rectangle(cellBounds.X + s, cellBounds.Bottom - h - s, 15, h);

            switch (this.EditMode)
            {
                case CellEditMode.None:
                case CellEditMode.Edit:
                    break;
                case CellEditMode.EditOrDelete:
                    if (this._Focused)
                        this.PaintButton(graphics, cellBounds, btnArea, PicLibraryColorList.Minus_FromFile, false, CellAreaType.ButtonMinus);
                    break;
                case CellEditMode.AddNew:
                    // if (this._Focused || this._WithMouse)
                    //     this.PaintButton(graphics, cellBounds, btnArea, PicLibrary7px.Plus_FromFile, false, CellAreaType.ButtonPlus);
                    break;
            }
        }
        /// <summary>
        /// Vykreslí jeden button
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cellBounds"></param>
        /// <param name="btnArea"></param>
        /// <param name="image"></param>
        /// <param name="p"></param>
        /// <param name="cellAreaType"></param>
        private void PaintButton(System.Drawing.Graphics graphics, System.Drawing.Rectangle cellBounds, System.Drawing.Rectangle btnArea, System.Drawing.Image image, bool pressed, CellAreaType areaType)
        {
            Rectangle imgArea = Rectangle.Round(GetCenterArea(btnArea, image.Size));
            System.Windows.Forms.VisualStyles.PushButtonState state = (pressed ? System.Windows.Forms.VisualStyles.PushButtonState.Pressed : System.Windows.Forms.VisualStyles.PushButtonState.Normal);
            ButtonRenderer.DrawButton(graphics, btnArea, image, imgArea, false, state);

            // Klikací mapa:
            Rectangle relArea = GetRelativeBtnArea(btnArea, cellBounds.Location);                           // Relativní souřadnice buttonu
            this._InnerAreas.Add(new KeyValuePair<CellAreaType, System.Drawing.Rectangle>(areaType, relArea));
        }
        /// <summary>
        /// Vrátí RectangleF, který má shodný střed jako daný RectangleF, a má danou velikost.
        /// </summary>
        /// <param name="outerArea"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        private static System.Drawing.RectangleF GetCenterArea(System.Drawing.RectangleF outerArea, System.Drawing.SizeF size)
        {
            PointF center = new System.Drawing.PointF(outerArea.X + outerArea.Width / 2F, outerArea.Y + outerArea.Height / 2F);
            RectangleF centerArea = new System.Drawing.RectangleF(center.X - size.Width / 2F, center.Y - size.Height / 2F, size.Width, size.Height);
            return centerArea;
        }
        /// <summary>
        /// Připraví styl Border pro aktuální stav buňky
        /// </summary>
        /// <param name="advancedBorderStyle"></param>
        private void PaintBorderPrepareStyle(DataGridViewAdvancedBorderStyle advancedBorderStyle)
        {
            bool isActive = ((this._WithMouse || this._Focused) && this.EditMode != CellEditMode.None);
            if (isActive)
            {
                if (this._MouseDownArea == CellAreaType.Cell)
                {
                    advancedBorderStyle.Left = DataGridViewAdvancedCellBorderStyle.Inset;
                    advancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.Inset;
                    advancedBorderStyle.Right = DataGridViewAdvancedCellBorderStyle.Outset;
                    advancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.Outset;
                }
                else
                {
                    advancedBorderStyle.Left = DataGridViewAdvancedCellBorderStyle.OutsetPartial;
                    advancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.OutsetPartial;
                    advancedBorderStyle.Right = DataGridViewAdvancedCellBorderStyle.Inset;
                    advancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.Inset;
                }
            }
            else
            {
                advancedBorderStyle.Left = DataGridViewAdvancedCellBorderStyle.None;
                advancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None;
                advancedBorderStyle.Right = DataGridViewAdvancedCellBorderStyle.Single;
                advancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.Single;
            }
        }
        /// <summary>
        /// Určí relativní prostor buttonu z jeho absolutní pozice (btnArea, v souřadnicích celého controlu) 
        /// vzhledem k danému bodu (pozice počátku zdejší buňky, v tomto souřadném systému chodí pozice myši do eventů Mouse)
        /// </summary>
        /// <param name="btnArea"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        private System.Drawing.Rectangle GetRelativeBtnArea(System.Drawing.Rectangle btnArea, System.Drawing.Point point)
        {
            return new System.Drawing.Rectangle(btnArea.X - point.X, btnArea.Y - point.Y, btnArea.Width, btnArea.Height);
        }
        /// <summary>
        /// Určí druh prostoru v buňce pro danou relativní souřadnici
        /// </summary>
        /// <param name="cellPoint"></param>
        /// <returns></returns>
        protected CellAreaType FindCellArea(Point cellPoint)
        {
            KeyValuePair<CellAreaType, Rectangle> areaKv = this._InnerAreas.LastOrDefault(kv => kv.Value.Contains(cellPoint));
            if (areaKv.Value.IsEmpty) return CellAreaType.Cell;
            return areaKv.Key;
        }
        /// <summary>
        /// Oblasti v buňce, určují případnou aktivitu myši po kliknutí na určitý bod
        /// </summary>
        protected enum CellAreaType { None, Border, Cell, ButtonPlus, ButtonMinus }
        #endregion
        #region Property
        /// <summary>
        /// Parent buňky = položka s barevnou sadou
        /// </summary>
		[PersistingEnabled(false)]
		public ColorItem Parent { get; private set; }
        /// <summary>
        /// Index barvy v rámci parenta
        /// </summary>
        public int ColorIndex { get; private set; }
        /// <summary>
        /// Aktuální hodnota barvy
        /// </summary>
        public System.Drawing.Color ColorValue
        {
            get { return this._ColorValue; }
            set { this._ColorValue = value; this.RePaint(); }
        }
        #endregion
        #region Události
        /// <summary>
        /// Událost, kdy uživatel mění barvu - kliknul na barvu, chce nabídku barev.
        /// </summary>
        protected void OnColorChange()
        {
            bool editable = (this.EditMode == CellEditMode.Edit || this.EditMode == CellEditMode.EditOrDelete || this.EditMode == CellEditMode.AddNew);
            if (!editable) return;

            Color value = this.ColorValue;
            if (value.IsEmpty) value = Color.White;

            if (DialogColor.SelectColor(ref value))
            {
                this.ColorValue = value;
                if (this.ColorIndex < 0)
                    this.Parent.AddColor(value);
                else
                    this.Parent.SetColor(value, this.ColorIndex);
            }
        }
        protected void OnColorAdd()
        {
            if (this.EditMode != CellEditMode.AddNew) return;
        }
        protected void OnColorDelete()
        {
            if (this.EditMode != CellEditMode.EditOrDelete) return;
            this.Parent.RemoveColorAt(this.ColorIndex);

            this.RePaint();
        }
		#endregion
        #region Statické služby pro Color
        internal static System.Drawing.Color ColorShift(System.Drawing.Color color, int shift)
        {
            int a = color.A;

            int r = Math.Max(Math.Min(color.R + shift, 255), 0);
            int g = Math.Max(Math.Min(color.G + shift, 255), 0);
            int b = Math.Max(Math.Min(color.B + shift, 255), 0);

            return System.Drawing.Color.FromArgb(a, r, g, b);
        }
        /// <summary>
        /// Ze zadané barvy (color) vytvoří dvě barvy (out color1 a out color2), mezi nimiž je daný rozdíl (diff), a které leží souměrně okolo zadané barvy.
        /// Číselně například: pro barvu 100 a diff = 20 vrátí barvu color1 = 90 a color2 = 110.
        /// Pro hodnoty blízko okrajům vrací jednu barvu na okraji, a druhou barvu o daný rozdíl vzdálenou, bez ohledu na symetrii.
        /// Například pro barvu 5 a diff = 20 vrátí barvu color1 = 0 a color2 = 20.
        /// </summary>
        /// <param name="color"></param>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <param name="diff"></param>
        internal static void ColorRange(System.Drawing.Color color, out System.Drawing.Color color1, out System.Drawing.Color color2, int diff)
        {
            ColorRange(color, out color1, out color2, diff, diff, diff);
        }
        internal static void ColorRange(System.Drawing.Color color, out System.Drawing.Color color1, out System.Drawing.Color color2, int difR, int difG, int difB)
        {
            int a1, a2, r1, r2, g1, g2, b1, b2;
            a1 = color.A;
            a2 = a1;
            ColorRangePart(color.R, difR, out r1, out r2);
            ColorRangePart(color.G, difG, out g1, out g2);
            ColorRangePart(color.B, difB, out b1, out b2);
            color1 = System.Drawing.Color.FromArgb(a1, r1, g1, b1);
            color2 = System.Drawing.Color.FromArgb(a2, r2, g2, b2);
        }
        internal static void ColorRangePart(int partIn, int diff, out int partLo, out int partHi)
        {
            if (diff > 255)
                diff = 255;
            int dif2 = diff / 2;
            if (partIn - dif2 < 0)
            {
                partLo = 0;
                partHi = diff;
            }
            else if (partIn + dif2 > 255)
            {
                partLo = 255 - diff;
                partHi = 255;
            }
            else
            {
                partLo = partIn - dif2;
                partHi = partLo + diff;
            }
        }
        #endregion
    }
    #endregion
    #region class PicLibrary7px
    internal static class PicLibraryColorList
    {
        #region Image Minus
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku minus.png.
        /// Vrací přímou referenci na objekt v paměti = volání je velice rychlé (pod 1 mikrosekundu), 
        /// ale protože se vrací živá reference, pak zásahy do vráceného objektu se projeví v objektu v paměti = natrvalo.
        /// Případně je možno vyvolat metodu Minus_Reset(), která zajistí regenerování obrázku z jeho definice.
        /// Bezpečnější je používání property Minus, která vrací vždy nový objekt.
        /// Pro používání pro Button.Image, kde bude nastavováno Button.Enabled = false; je třeba použít property Minus_FromFile.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\minus.png
        /// </remarks>
        public static System.Drawing.Image Minus_Cached
        {
            get
            {
                if (_Minus == null) _Minus = Minus;
                return _Minus;
            }
        }
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku minus.png.
        /// Nelze používat jako Image pro Buttony, kde bude nastavováno Enabled = false (pak dojde k chybě .NET: Ot of memory).
        /// Pak je třeba použít Image Minus_FromFile.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití Minus_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property Minus_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\minus.png
        /// </remarks>
        public static System.Drawing.Image Minus { get { return _ImageCreateFrom(_Minus_string, null); } }
        /// <summary>
        /// Vrátí obrázek, načtený ze souboru minus.png.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití Minus_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property Minus_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\minus.png
        /// </remarks>
        public static System.Drawing.Image Minus_FromFile { get { return _ImageCreateFrom(_Minus_string, "minus.png"); } }
        /// <summary>
        /// Vygeneruje a vrátí string, který definuje obsah souboru Minus
        /// </summary>
        /// <returns></returns>
        private static string _Minus_string()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder(256);
            sb.Append("iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3");
            sb.Append("YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAC9JREFUGFdj+P//PwMujFMCpIFhsbq0w1JN6QZ0vERdNoEBIijzHwvej18n2Q4CANqOc0A1abMBAAAAAElFTkSuQmCC");
            return sb.ToString();
        }
        /// <summary>
        /// Resetuje obrázek v paměti.
        /// Následující použití property Minus_Direct si vytvoří nový, korektní - podle jeho originální deklarace.
        /// Tuto metodu je vhodné použít v situaci, kdy je správnost obrázku v paměti nejistá.
        /// </summary>
        public static void Minus_Reset()
        {
            _Minus = null;
        }
        /// <summary>
        /// Úložiště objektu v paměti, při prvním použití Minus_Direct je objekt naplněn a následně využíván.
        /// </summary>
        private static System.Drawing.Image _Minus = null;
        #endregion
        #region Image Plus
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku plus.png.
        /// Vrací přímou referenci na objekt v paměti = volání je velice rychlé (pod 1 mikrosekundu), 
        /// ale protože se vrací živá reference, pak zásahy do vráceného objektu se projeví v objektu v paměti = natrvalo.
        /// Případně je možno vyvolat metodu Plus_Reset(), která zajistí regenerování obrázku z jeho definice.
        /// Bezpečnější je používání property Plus, která vrací vždy nový objekt.
        /// Pro používání pro Button.Image, kde bude nastavováno Button.Enabled = false; je třeba použít property Plus_FromFile.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\plus.png
        /// </remarks>
        public static System.Drawing.Image Plus_Cached
        {
            get
            {
                if (_Plus == null) _Plus = Plus;
                return _Plus;
            }
        }
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku plus.png.
        /// Nelze používat jako Image pro Buttony, kde bude nastavováno Enabled = false (pak dojde k chybě .NET: Ot of memory).
        /// Pak je třeba použít Image Plus_FromFile.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití Plus_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property Plus_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\plus.png
        /// </remarks>
        public static System.Drawing.Image Plus { get { return _ImageCreateFrom(_Plus_string, null); } }
        /// <summary>
        /// Vrátí obrázek, načtený ze souboru plus.png.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití Plus_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property Plus_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\plus.png
        /// </remarks>
        public static System.Drawing.Image Plus_FromFile { get { return _ImageCreateFrom(_Plus_string, "plus.png"); } }
        /// <summary>
        /// Vygeneruje a vrátí string, který definuje obsah souboru Plus
        /// </summary>
        /// <returns></returns>
        private static string _Plus_string()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder(280);
            sb.Append("iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3");
            sb.Append("YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAD9JREFUGFdj+P//PwMIMzDsdgDiBhANF0OSBEkAVe1uQIghdByASoJooMIdASDjYDpAupDxfGS7MHXitROfawFyfFwc");
            sb.Append("RiXTNwAAAABJRU5ErkJggg==");
            return sb.ToString();
        }
        /// <summary>
        /// Resetuje obrázek v paměti.
        /// Následující použití property Plus_Direct si vytvoří nový, korektní - podle jeho originální deklarace.
        /// Tuto metodu je vhodné použít v situaci, kdy je správnost obrázku v paměti nejistá.
        /// </summary>
        public static void Plus_Reset()
        {
            _Plus = null;
        }
        /// <summary>
        /// Úložiště objektu v paměti, při prvním použití Plus_Direct je objekt naplněn a následně využíván.
        /// </summary>
        private static System.Drawing.Image _Plus = null;
        #endregion
        #region Image New
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku new.png.
        /// Vrací přímou referenci na objekt v paměti = volání je velice rychlé (pod 1 mikrosekundu), 
        /// ale protože se vrací živá reference, pak zásahy do vráceného objektu se projeví v objektu v paměti = natrvalo.
        /// Případně je možno vyvolat metodu New_Reset(), která zajistí regenerování obrázku z jeho definice.
        /// Bezpečnější je používání property New, která vrací vždy nový objekt.
        /// Pro používání pro Button.Image, kde bude nastavováno Button.Enabled = false; je třeba použít property New_FromFile.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\new.png
        /// </remarks>
        public static System.Drawing.Image New_Cached
        {
            get
            {
                if (_New == null) _New = New;
                return _New;
            }
        }
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku new.png.
        /// Nelze používat jako Image pro Buttony, kde bude nastavováno Enabled = false (pak dojde k chybě .NET: Ot of memory).
        /// Pak je třeba použít Image New_FromFile.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití New_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property New_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\new.png
        /// </remarks>
        public static System.Drawing.Image New { get { return _ImageCreateFrom(_New_string, null); } }
        /// <summary>
        /// Vrátí obrázek, načtený ze souboru new.png.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití New_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property New_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\new.png
        /// </remarks>
        public static System.Drawing.Image New_FromFile { get { return _ImageCreateFrom(_New_string, "new.png"); } }
        /// <summary>
        /// Vygeneruje a vrátí string, který definuje obsah souboru New
        /// </summary>
        /// <returns></returns>
        private static string _New_string()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder(468);
            sb.Append("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3");
            sb.Append("YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAM1JREFUOE9jYBi0oP3/bSEgrgbiVyCaZIcCNTkC8X8QTju47JP/tEbSDAFqVIYZkLJ/yX+gASkEXQHUwAHCIIVAWg1m");
            sb.Append("QObx1UQbcAmmCR+N1SVADabEaAapAXoHhB+hGASUSCHRgEUYLgEFFNT0/+FL+8AxAMIZR1dCbJ3e9D94XgfMBZ54AxU5FrJOrgVpKgFpANIsQCxCTIzAozHv4maQAXUE");
            sb.Append("NSErALrAqO3frU9F13f+D13YDTJgAkkGQJ1rBNT4AYgXALEsyQbQRQMACpn/ZxZDemgAAAAASUVORK5CYII=");
            return sb.ToString();
        }
        /// <summary>
        /// Resetuje obrázek v paměti.
        /// Následující použití property New_Direct si vytvoří nový, korektní - podle jeho originální deklarace.
        /// Tuto metodu je vhodné použít v situaci, kdy je správnost obrázku v paměti nejistá.
        /// </summary>
        public static void New_Reset()
        {
            _New = null;
        }
        /// <summary>
        /// Úložiště objektu v paměti, při prvním použití New_Direct je objekt naplněn a následně využíván.
        /// </summary>
        private static System.Drawing.Image _New = null;
        #endregion
        #region Image Newb
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku newb.png.
        /// Vrací přímou referenci na objekt v paměti = volání je velice rychlé (pod 1 mikrosekundu), 
        /// ale protože se vrací živá reference, pak zásahy do vráceného objektu se projeví v objektu v paměti = natrvalo.
        /// Případně je možno vyvolat metodu Newb_Reset(), která zajistí regenerování obrázku z jeho definice.
        /// Bezpečnější je používání property Newb, která vrací vždy nový objekt.
        /// Pro používání pro Button.Image, kde bude nastavováno Button.Enabled = false; je třeba použít property Newb_FromFile.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\newb.png
        /// </remarks>
        public static System.Drawing.Image Newb_Cached
        {
            get
            {
                if (_Newb == null) _Newb = Newb;
                return _Newb;
            }
        }
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku newb.png.
        /// Nelze používat jako Image pro Buttony, kde bude nastavováno Enabled = false (pak dojde k chybě .NET: Ot of memory).
        /// Pak je třeba použít Image Newb_FromFile.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití Newb_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property Newb_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\newb.png
        /// </remarks>
        public static System.Drawing.Image Newb { get { return _ImageCreateFrom(_Newb_string, null); } }
        /// <summary>
        /// Vrátí obrázek, načtený ze souboru newb.png.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití Newb_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property Newb_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\ColorListGrid\ColorListGrid\pic\newb.png
        /// </remarks>
        public static System.Drawing.Image Newb_FromFile { get { return _ImageCreateFrom(_Newb_string, "newb.png"); } }
        /// <summary>
        /// Vygeneruje a vrátí string, který definuje obsah souboru Newb
        /// </summary>
        /// <returns></returns>
        private static string _Newb_string()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder(468);
            sb.Append("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3");
            sb.Append("YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAM5JREFUOE9jYBi04MT/T0JAXA3Er0A0yQ4FanIE4v8gvPrF7U8TLh0mzRCgRmWYASuf3/oPNCCFoCuAGjhAGKQQSKvB");
            sb.Append("DFj36h7RBlyCacJHY3UJUIMpMZpBaoDeAeFHKAYBJVJINGARhktAAQU1/f+sW2fAMQDCa1/dhdp65P/UaydgLvDEG6jIsbD+9X2QphKQBiDNAsQixMQIPBo3v3sEMqCO");
            sb.Append("oCZkBUAXGB3/9+nT9o9P/s+4cQpkwASSDIA61wio8QMQLwBiWZINoIsGAEyZKpElrnT+AAAAAElFTkSuQmCC");
            return sb.ToString();
        }
        /// <summary>
        /// Resetuje obrázek v paměti.
        /// Následující použití property Newb_Direct si vytvoří nový, korektní - podle jeho originální deklarace.
        /// Tuto metodu je vhodné použít v situaci, kdy je správnost obrázku v paměti nejistá.
        /// </summary>
        public static void Newb_Reset()
        {
            _Newb = null;
        }
        /// <summary>
        /// Úložiště objektu v paměti, při prvním použití Newb_Direct je objekt naplněn a následně využíván.
        /// </summary>
        private static System.Drawing.Image _Newb = null;
        #endregion
        #region Image DocNew
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku document-new-5.png.
        /// Vrací přímou referenci na objekt v paměti = volání je velice rychlé (pod 1 mikrosekundu), 
        /// ale protože se vrací živá reference, pak zásahy do vráceného objektu se projeví v objektu v paměti = natrvalo.
        /// Případně je možno vyvolat metodu DocNew_Reset(), která zajistí regenerování obrázku z jeho definice.
        /// Bezpečnější je používání property DocNew, která vrací vždy nový objekt.
        /// Pro používání pro Button.Image, kde bude nastavováno Button.Enabled = false; je třeba použít property DocNew_FromFile.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\document-new-5.png
        /// </remarks>
        public static System.Drawing.Image DocNew_Cached
        {
            get
            {
                if (_DocNew == null) _DocNew = DocNew;
                return _DocNew;
            }
        }
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku document-new-5.png.
        /// Nelze používat jako Image pro Buttony, kde bude nastavováno Enabled = false (pak dojde k chybě .NET: Ot of memory).
        /// Pak je třeba použít Image DocNew_FromFile.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití DocNew_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property DocNew_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\document-new-5.png
        /// </remarks>
        public static System.Drawing.Image DocNew { get { return _ImageCreateFrom(_DocNew_string, null); } }
        /// <summary>
        /// Vrátí obrázek, načtený ze souboru document-new-5.png.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití DocNew_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property DocNew_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\document-new-5.png
        /// </remarks>
        public static System.Drawing.Image DocNew_FromFile { get { return _ImageCreateFrom(_DocNew_string, "document-new-5.png"); } }
        /// <summary>
        /// Vygeneruje a vrátí string, který definuje obsah souboru DocNew
        /// </summary>
        /// <returns></returns>
        private static string _DocNew_string()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder(1876);
            sb.Append("iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAAK/INwWK6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAAASAAAAEgARslrPgAAAAl2cEFn");
            sb.Append("AAAAFgAAABYA3MXpWAAAA3VJREFUOMu1lV1MHFUUx393Zndgd2lBATXd1gQ/a6Sx2mpIilS0JTGWRB8kqQ9+vOmbH1GjD33T6FN9MakvTZpommiUpNvEhkRILKK2CgVM");
            sb.Append("W8EsCAHdAuV72d2Ze48Ps7M7YAn1wZuc3JM7M7/7P+fce0aJCP/HiATOtsff+Pxw25NHq6sqlafNlrtJyBEF0YitBodHFi9duNiOZfUiIogIh949ncvLzQ8TMl1cOzM4");
            sb.Append("I07z253xlnfKihOxShX9D6GKlM0Ajg0Jx8Z2nIhtqTJYayM6nJtNwjfGB4WhxvjggmcQI0a24KwbRorgjdBgBiwLlPLtpsASmJTTEGwQPBRgtQBa++tbgsPKwkoDX2vI");
            sb.Append("a1ARmF6BQh6wtwBvDF2krNwI5D0oaPAEoqYYgfJtU3App1IGlSIwkNM+VGwwnr8mpvy9telRCs8h9Z6BrOtDiUBhLY8W0BLUwH/7hmAdDt2Ufc+DHEACVBxWRn9n6fjz");
            sb.Append("rJ3vhEooVMTAihsiiRunoqQ2VDhXQ8GC5YkxZru+4pbDHeTSI+zak2Zu7RKLi8+yo/cUb2bO1BzITP4bHD5aRsAtQj0NVhVc60mxq36I+e45FmbraWjZiTsCuVMf0NF6");
            sb.Append("gtYfl3aPdi5bVjj8QJ3W4AYF8vy8GgGjoa6tg7mlJA3N1VSmv8RIBfZoit0HUwyMPciH39/TD7YpKZ5ahhUPtim/MLqo2BRPgdgwO3yZ7J8jLEzVkD2R4rFjT6Bieaof");
            sb.Append("qmD+6yv0de7HSrqN9R4vhXqFD9Oshwa+6xa41vUJ9z9yO3c/k0BWm1DxBFZ9EnSe6J4aXnu0ByeWvfPvb5InS2BFqMmEocbfTNkREo3tTGX68S4v4oz9QO0Dh5DcdZST");
            sb.Append("pzC8yLcDe7HddHbfr0Nd1saToNkADTZxLepa24m3vYcnce564Sn+ONnHSv8QU58NUNMUx6u1SJ3dnipcXXuupNiybSvmQAJQdrlrlVJkQMVgrvML9jXOsDKdYHyikdu8");
            sb.Append("NLMLByj0rnL05fM8/PP1lsw5rBL4r4n03Kc9M3fcGnPIe7Ku2QTXmgpYXthJX/c5phtfJXnfPAejV5hM7qCbF7n3o9dpGP/uQhUYFfxM1d5XmonWvkUkUoGEb32xAEG+");
            sb.Append("og7K9ZDK7d7+zMW6s0d+afr4p4bx4zz9G9n5q8cGT79/RE+afwCOJ1BIlRV/kgAAACV0RVh0Y3JlYXRlLWRhdGUAMjAwOS0xMS0xNVQxNjowODo0NC0wNzowMHaWzkcA");
            sb.Append("AAAldEVYdGRhdGU6Y3JlYXRlADIwMTAtMDItMjBUMjM6MjY6MTUtMDc6MDAGO1yBAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDEwLTAxLTExVDA5OjE5OjI3LTA3OjAwgwoh");
            sb.Append("TAAAADV0RVh0TGljZW5zZQBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9MR1BMLzIuMS87wbQYAAAAJXRFWHRtb2RpZnktZGF0ZQAyMDA5LTExLTE1");
            sb.Append("VDE2OjA4OjQ0LTA3OjAwKSe4cwAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAANdEVYdFNvdXJjZQBOdXZvbGGsTzXxAAAANHRFWHRTb3VyY2Vf");
            sb.Append("VVJMAGh0dHA6Ly93d3cuaWNvbi1raW5nLmNvbS9wcm9qZWN0cy9udXZvbGEvdj20UgAAAABJRU5ErkJggg==");
            return sb.ToString();
        }
        /// <summary>
        /// Resetuje obrázek v paměti.
        /// Následující použití property DocNew_Direct si vytvoří nový, korektní - podle jeho originální deklarace.
        /// Tuto metodu je vhodné použít v situaci, kdy je správnost obrázku v paměti nejistá.
        /// </summary>
        public static void DocNew_Reset()
        {
            _DocNew = null;
        }
        /// <summary>
        /// Úložiště objektu v paměti, při prvním použití DocNew_Direct je objekt naplněn a následně využíván.
        /// </summary>
        private static System.Drawing.Image _DocNew = null;
        #endregion
        #region Image DocOpen
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku document-open-4.png.
        /// Vrací přímou referenci na objekt v paměti = volání je velice rychlé (pod 1 mikrosekundu), 
        /// ale protože se vrací živá reference, pak zásahy do vráceného objektu se projeví v objektu v paměti = natrvalo.
        /// Případně je možno vyvolat metodu DocOpen_Reset(), která zajistí regenerování obrázku z jeho definice.
        /// Bezpečnější je používání property DocOpen, která vrací vždy nový objekt.
        /// Pro používání pro Button.Image, kde bude nastavováno Button.Enabled = false; je třeba použít property DocOpen_FromFile.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\document-open-4.png
        /// </remarks>
        public static System.Drawing.Image DocOpen_Cached
        {
            get
            {
                if (_DocOpen == null) _DocOpen = DocOpen;
                return _DocOpen;
            }
        }
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku document-open-4.png.
        /// Nelze používat jako Image pro Buttony, kde bude nastavováno Enabled = false (pak dojde k chybě .NET: Ot of memory).
        /// Pak je třeba použít Image DocOpen_FromFile.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití DocOpen_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property DocOpen_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\document-open-4.png
        /// </remarks>
        public static System.Drawing.Image DocOpen { get { return _ImageCreateFrom(_DocOpen_string, null); } }
        /// <summary>
        /// Vrátí obrázek, načtený ze souboru document-open-4.png.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití DocOpen_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property DocOpen_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\document-open-4.png
        /// </remarks>
        public static System.Drawing.Image DocOpen_FromFile { get { return _ImageCreateFrom(_DocOpen_string, "document-open-4.png"); } }
        /// <summary>
        /// Vygeneruje a vrátí string, který definuje obsah souboru DocOpen
        /// </summary>
        /// <returns></returns>
        private static string _DocOpen_string()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder(1740);
            sb.Append("iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAA3XAAAN1wFCKJt4AAAACXZwQWcAAAAWAAAAFgDcxelYAAAD");
            sb.Append("EUlEQVQ4y52VTWhcVRTHf/e9N2+SsS2CZmEDUpQIRXDhQlqL+IHOQlyKIM80K3d17dKtiKtutC5ExKy6FoyCKKTWNviF3WgWtWQa0kxNOunMm/fuO/ccF5NOZ6ZRkx64");
            sb.Append("vHd43N/933P+716XZRn/FVUoC+dcbGbOOQfAnZe0lv7Rz8vn0zRtT85LALz38ezs7OG9wOsbrfpnn36Oc25sACwufnF86ZulFeApYOce8Nzc3O/OuccBmwSbGWtra5Rl");
            sb.Append("OcxDCKgqp08v0Ol0Hl35aeVC2ffPpGnaHwOLyPH5+XlCCJgZqgqAqvLBh+8TRRGXLl8aW/DkiRMAnDnzjjv3ycdPLl9YPovx9iTYRMS1Wi1EBFVFVTEznHOkaUrzlSZm");
            sb.Append("NlQN0G63ERGePXnKXfzxhzdUJsAhBFNVJyLDbd4ZAEmSsPT1V4QQhopffOElvPeDxIGqRhAxobgykYoQAr66CxYRcDG4mGbz1TG1o88kqWMW6Xrt5anvjl3z2eqquizL");
            sb.Append("aDQasrCwEF+80uL8L0IU3V3ZzIjcSD7R313+7u5ccM61L5978+iwxiEENm8rzz19jNdOPTGcMPDtv/t89FPuJX7vo29nsuwtG9ZYRMhLY2a6zman4PpWn4PEVC3m4cM1");
            sb.Append("ojjqTrqCXgWPPVAHg2SkHPsJNSh9IHJRZwiuqkHz8spxpFHHDJJ4/+BeIUynMd4LLmJ7zG4igdzDoUZtYJd9cIMaeRmQoEynNYq+B7g5qpgQAkU1aIcXvQegxu5fOci9");
            sb.Append("KGrjDun0SkztxqhiFRH63vDB6BaBXil40T0Be5ajjNm8lSOq62OKKxF8MLa7Fa2tPkH/HzYaO7WIrU5RWdDNIRjQvAzUazG3+oIcEApQVsZ2t/Q49/comG6hPPLQER5s");
            sb.Append("JByaOpjVACLn6PVKMbUtgGRxcTFpNpv250bJzU7B9z9fPTAUIJjS7eWp9LavEQ8U1/M8//LX1fbrVaOe3O4V94F1ZmZS7mwsXzn/7tXfdk+BGnAUmBktzX2EMrie/sqy");
            sb.Append("rEgAAa4DNxg/Uw4atguvAP4B8QDyvvsXDgUAAAAldEVYdGNyZWF0ZS1kYXRlADIwMDktMTEtMTBUMTk6Mzg6MjAtMDc6MDCAfY3xAAAAJXRFWHRkYXRlOmNyZWF0ZQAy");
            sb.Append("MDEwLTAyLTIwVDIzOjI2OjE1LTA3OjAwBjtcgQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMC0wMS0xMVQwODo1NjozMS0wNzowMLA05WIAAAAydEVYdExpY2Vuc2UAaHR0");
            sb.Append("cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QdWJsaWNfZG9tYWluP/3qzwAAACV0RVh0bW9kaWZ5LWRhdGUAMjAwOS0xMS0xMFQxOTozODoyMC0wNzowMN/M+8UAAAAZ");
            sb.Append("dEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAGXRFWHRTb3VyY2UAVGFuZ28gSWNvbiBMaWJyYXJ5VM/tggAAADp0RVh0U291cmNlX1VSTABodHRwOi8v");
            sb.Append("dGFuZ28uZnJlZWRlc2t0b3Aub3JnL1RhbmdvX0ljb25fTGlicmFyebzIrdYAAAAASUVORK5CYII=");
            return sb.ToString();
        }
        /// <summary>
        /// Resetuje obrázek v paměti.
        /// Následující použití property DocOpen_Direct si vytvoří nový, korektní - podle jeho originální deklarace.
        /// Tuto metodu je vhodné použít v situaci, kdy je správnost obrázku v paměti nejistá.
        /// </summary>
        public static void DocOpen_Reset()
        {
            _DocOpen = null;
        }
        /// <summary>
        /// Úložiště objektu v paměti, při prvním použití DocOpen_Direct je objekt naplněn a následně využíván.
        /// </summary>
        private static System.Drawing.Image _DocOpen = null;
        #endregion
        #region Image DocSave
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku media-floppy-3.png.
        /// Vrací přímou referenci na objekt v paměti = volání je velice rychlé (pod 1 mikrosekundu), 
        /// ale protože se vrací živá reference, pak zásahy do vráceného objektu se projeví v objektu v paměti = natrvalo.
        /// Případně je možno vyvolat metodu DocSave_Reset(), která zajistí regenerování obrázku z jeho definice.
        /// Bezpečnější je používání property DocSave, která vrací vždy nový objekt.
        /// Pro používání pro Button.Image, kde bude nastavováno Button.Enabled = false; je třeba použít property DocSave_FromFile.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\media-floppy-3.png
        /// </remarks>
        public static System.Drawing.Image DocSave_Cached
        {
            get
            {
                if (_DocSave == null) _DocSave = DocSave;
                return _DocSave;
            }
        }
        /// <summary>
        /// Vrátí obrázek, vytvořený na základě obrázku media-floppy-3.png.
        /// Nelze používat jako Image pro Buttony, kde bude nastavováno Enabled = false (pak dojde k chybě .NET: Ot of memory).
        /// Pak je třeba použít Image DocSave_FromFile.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití DocSave_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property DocSave_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\media-floppy-3.png
        /// </remarks>
        public static System.Drawing.Image DocSave { get { return _ImageCreateFrom(_DocSave_string, null); } }
        /// <summary>
        /// Vrátí obrázek, načtený ze souboru media-floppy-3.png.
        /// Vrací vždy novou instanci = volání je při častém používání výrazně (až 1000krát) pomalejší než použití DocSave_Cached
        /// (kde ale hrozí nebezpečí pokažení obrázku v paměti).
        /// Čas pro vytvoření jednoho Image (tj. každé jednotlivé čtení této property) pro obrázek velikosti 32x32 px (32bpp) je průměrně 350 mikrosekund.
        /// Pokud je třeba používat obrázek často a rychle, je možné využít property DocSave_Cached.
        /// </summary>
        /// <remarks>
        /// Plné jméno vstupního souboru:
        /// C:\David\_Cs2010\TraceVisualiser\TraceVisualiser\Pics\Pic22\media-floppy-3.png
        /// </remarks>
        public static System.Drawing.Image DocSave_FromFile { get { return _ImageCreateFrom(_DocSave_string, "media-floppy-3.png"); } }
        /// <summary>
        /// Vygeneruje a vrátí string, který definuje obsah souboru DocSave
        /// </summary>
        /// <returns></returns>
        private static string _DocSave_string()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder(1784);
            sb.Append("iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAAK/INwWK6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAAASAAAAEgARslrPgAAAAl2cEFn");
            sb.Append("AAAAFgAAABYA3MXpWAAAAzJJREFUOMu1lb9rZFUUxz/n3Dvz5mUyycZsNisE49oJNlZ2C4qNiOWWgn+GjTY2QsBCi22sRbFw2SrarKKwjSy6ElBYtkkw7I8E4s7Mmx/v");
            sb.Append("nmNx30wmmAWbXHice4v3ud9zzvfeK+7ORQy9ECoQZxPRnXd725ufrl3uvliSpg64OwjgnEa8ic1/Ygy8iCfPfNh/+PXnpO++cE+TOXjlpSufvP/Zjdfe2Bbe3DZM2iSH");
            sb.Append("lJzk4A4x5BR1RhZQG3H7jwm7B+v8snPy8cne7j3gzhzcXStf2Nws6cUBW2sB00hKME1QG6QEKhAVQoDQRHWjSEc8OTyhs7bcOUGvnQG7eT2ujLqEVDspQF1naJ0yuE4g");
            sb.Append("kpUHzbHlCQklV7ausi+/GpifqbEqGKAiBBVUT1srC1/dbAA5AwNUhVaEIKfFP22e5L1UZL6OoaHBvGEuTSYz9Y2Q2vL6P2AVMAMNOleqCnHmBl/YJCyUSLOY5JlxruLk");
            sb.Append("uTmL7laBdgtizKCoGTaxLEQQVCXPzwMHyZYCZTCcMrUx4NnLnqMlx8gxmWMGiTEaWk0ZzwEj0FK496jF/UeRZyOnNsecBpLTNW+UB+i0nLpe4p9RQMlOObfGAE9G8Hj/");
            sb.Append("KZekT4iRZJAMzCNGxCwSNLJ/HPjzILLxcouiK5Tl2fvhTCnMhWoC5egpH75Xsr6+BGJMRr5Qv0RRJG79VPPB9wXrV3uEXhYgi71ZbJ47jW2UleWC3Z8fc/Obv9HYIrYL");
            sb.Append("NEY0BjqFEtvO6kZAgjCtc+PDuXbT3OVkYEmoqiG3fujz42/CjbeHxBgwazSPndFkSnc14EGpE4TnuUIEElmx1S0GgwqXVdqdkmE1JoY4B0ttTGuju6KI5vsk2nNcEYMG");
            sb.Append("I5+gum5zeHjM9deFV68NOT5SVJXZmzCMxmgc6V4KmAiTugGH02LMwaOBTVsBOj1I3R5L3QHvXG/j7vSrBSlAGYzlFWVjq83AgAl0uzCsJiEf+gXww/vf3ryzM/mot3l5");
            sb.Append("xQd9+3JvTLsdyOfj7PMVFQ6OjaPqdwxBNHDcr+TB3a/2oHoAILOfRIoIxVsgr4AY/2vMLxEBE+j/Bdx195Fc1GP6L/vyjVEcOd0RAAAAJXRFWHRjcmVhdGUtZGF0ZQAy");
            sb.Append("MDA5LTExLTE1VDE2OjA4OjQyLTA3OjAwFUb7fQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMC0wMi0yMlQxNDoyMTozNi0wNzowMBGYXPgAAAAldEVYdGRhdGU6bW9kaWZ5");
            sb.Append("ADIwMTAtMDEtMTFUMDk6MTk6MDEtMDc6MDCi/xMLAAAANXRFWHRMaWNlbnNlAGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL0xHUEwvMi4xLzvBtBgA");
            sb.Append("AAAldEVYdG1vZGlmeS1kYXRlADIwMDktMTEtMTVUMTY6MDg6NDItMDc6MDBK941JAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA10RVh0U291");
            sb.Append("cmNlAE51dm9sYaxPNfEAAAA0dEVYdFNvdXJjZV9VUkwAaHR0cDovL3d3dy5pY29uLWtpbmcuY29tL3Byb2plY3RzL251dm9sYS92PbRSAAAAAElFTkSuQmCC");
            return sb.ToString();
        }
        /// <summary>
        /// Resetuje obrázek v paměti.
        /// Následující použití property DocSave_Direct si vytvoří nový, korektní - podle jeho originální deklarace.
        /// Tuto metodu je vhodné použít v situaci, kdy je správnost obrázku v paměti nejistá.
        /// </summary>
        public static void DocSave_Reset()
        {
            _DocSave = null;
        }
        /// <summary>
        /// Úložiště objektu v paměti, při prvním použití DocSave_Direct je objekt naplněn a následně využíván.
        /// </summary>
        private static System.Drawing.Image _DocSave = null;
        #endregion
        #region SPOLEČNÉ METODY PRO KONVERZI
        /// <summary>
        /// Vrátí Image z definice (string). Image generuje buď v paměti, anebo s pomocí souboru.
        /// Pokud není zadán parametr (cacheFileName) (když je null), generuje se Image v paměti.
        /// Pokud je soubor (cacheFileName) definován, pak se Image čte z něj.
        /// Pokud soubor neexistuje, nejprve se vytvoří.
        /// Umístění souboru (adresář) je dán property _ImageCacheDir, defaultně je to adresář (Sys:\Documents and Settings\All Users\Data aplikací\IconCache).
        /// Obsah obrázku definuje metoda getDataMethod.
        /// </summary>
        /// <param name="getDataMethod"></param>
        /// <param name="cacheFileName"></param>
        /// <returns></returns>
        private static System.Drawing.Image _ImageCreateFrom(_GetStringDelegate getDataMethod, string cacheFileName)
        {
            System.Drawing.Image image;
            if (cacheFileName == null)
            {
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream(Convert.FromBase64String(getDataMethod())))
                {
                    image = System.Drawing.Image.FromStream(ms);
                }
                return image;
            }
            string fileName = System.IO.Path.Combine(_ImageCacheDir, cacheFileName);
            if (!System.IO.File.Exists(fileName))
                System.IO.File.WriteAllBytes(fileName, Convert.FromBase64String(getDataMethod()));
            if (System.IO.File.Exists(fileName))
                return Image.FromFile(fileName);
            return null;
        }
        /// <summary>
        /// Obsahuje jméno adresáře, který slouží jako Cache pro obrázky systému.
        /// </summary>
        private static string _ImageCacheDir
        {
            get
            {
                if (__ImageCacheDir == null)
                    __ImageCacheDir = Noris.Tools.TraceVisualiser.Support.Steward.GetUserAppDataPath(@"IconCache\PicsCl7");
                return __ImageCacheDir;
            }
        }
        private static string __ImageCacheDir;
        /// <summary>
        /// Předpis pro metody, které generují obsah souboru s daty
        /// </summary>
        /// <returns></returns>
        private delegate string _GetStringDelegate();
        /// <summary>
        /// Vrátí Icon z dat (string), která jsou předána na vstup v kódování Base64
        /// </summary>
        /// <param name="data">Vstupní data v kódování Base64</param>
        /// <returns>Icon vytvořená z dat</returns>
        public static System.Drawing.Icon ConvertStringToIcon(string data)
        {
            System.Drawing.Icon icon;
            using (System.IO.MemoryStream ms = new System.IO.MemoryStream(Convert.FromBase64String(data)))
            {
                icon = new System.Drawing.Icon(ms);
            }
            return icon;
        }
        /// <summary>
        /// Vrátí Cursor z dat (string), která jsou předána na vstup v kódování Base64
        /// </summary>
        /// <param name="data">Vstupní data v kódování Base64</param>
        /// <returns>Cursor vytvořený z dat</returns>
        public static System.Windows.Forms.Cursor ConvertStringToCursor(string data)
        {
            System.Windows.Forms.Cursor cursor;
            using (System.IO.MemoryStream ms = new System.IO.MemoryStream(Convert.FromBase64String(data)))
            {
                cursor = new System.Windows.Forms.Cursor(ms);
            }
            return cursor;
        }
        #endregion
    }
    #endregion
}
